Implementation of String. Join in BCL
During development, sometimes a field in a List object needs to be spelled into a string using a separator. For example, in the in condition of an SQL statement, we usually need to convert an object like List <int> to a string like "1, 2, 3" and then use it as an in statement. So naturally, you can splice a string in a loop, so you can write the following general method: private static string GetStringFromList <T> (char seperator, IEnumerable <T> values) {if (seperator = null) return string. empty; if (values = null & values. count () = 0) return string. empty; String result; StringBuilder strBuilder; strBuilder = new StringBuilder (); foreach (T str in values) {strBuilder. append (str. toString (); strBuilder. append (seperator );} Result = strBuilder. toString (). the TrimEnd (seperator); return result;} method is actually very simple. first create a StringBuilder, Append the data to it, and finally remove the last extra separator. Later, we found that the string type in BCL provides the ready-made string. Join method, which has the same functions as the preceding method. So curious, I want to see how to implement such a simple function in BCL. Because most of the code of BCL is open-source, you can use the Reflector tool to view it, I used this tool before, but recently I saw Microsoft's Reference Source website. I can view the Source code online. For example, the implementation of the string class is as follows, you can see how the GetHashCode of string is implemented. Here we return to the Join method we want to view, which is implemented as follows: [ComVisible (false)] public static String Join <T> (String separator, IEnumerable <T> values) {if (values = null) throw new ArgumentNullException ("values"); Contract. ensures (Contract. result <String> ()! = Null); Contract. endContractBlock (); if (separator = null) separator = String. empty; using (IEnumerator <T> en = values. getEnumerator () {if (! En. MoveNext () return String. Empty; StringBuilder result = StringBuilderCache. Acquire (); if (en. Current! = Null) {// handle the case that the enumeration has null entries // and the case where their ToString () override is broken string value = en. current. toString (); if (value! = Null) result. Append (value);} while (en. MoveNext () {result. Append (separator); if (en. Current! = Null) {// handle the case that the enumeration has null entries // and the case where their ToString () override is broken string value = en. current. toString (); if (value! = Null) result. Append (value) ;}return StringBuilderCache. GetStringAndRelease (result) ;}} is the code simple. Compared with the previous manual implementation method, we found that the code we wrote looked very frustrated. This is the gap. In the String Join method, we can see a few points worth noting: at the beginning of the method, the Contract class is used for verification to assist in code writing. This is described in the previous article. Also, the necessary parameter validity verification is performed at the beginning of the method; timely judgment in the method and timely return. In implementation, the enumerator is used. The foreach statement in C # is actually the syntax sugar of this enumerator, so there is nothing to say here, it is worth mentioning that while (en. moveNext) avoid adding redundant strings at the end of the string in our method, and call TrimEnd to avoid unnecessary memory overhead. This is actually do {...} While (...), and while (...) {...} The difference between the two types of circulation bodies is reflected. In implementation, StringBuilder is not directly allocated to new, and the ToString method is not directly used when the string is returned. Instead, the StringBuilderCache class is used, which was previously translated. NET Program Performance essentials and optimization Suggestions This article introduces. This class is regarded as the cache of StringBuilder, because it is also an overhead to create StringBuilder for some small strings. The implementation of StringBuilder is as follows: // ==++ ==/// Copyright (c) Microsoft Corporation. all rights reserved. //// = -- =/* = ============================================ ***** Class: stringBuilderCache *** Purpose: provide a cached reusable instance of stringbuilder ** per thread it's an optimisation that reduces CES the ** number of instances constructed and collected. * *** Acquire-is used to get a string Builder to use of a ** particle size. it can be called any number of ** times, if a stringbuilder is in the cache then ** it will be returned and the cache emptied. ** subsequent callwill return a new stringbuilder. * *** A StringBuilder instance is cached in ** Thread Local Storage and so there is one per thread ***** Release-Place the specified builder in the cache if it is ** not too big. ** Stringbuilder shoshould not be used after it has ** been released. ** Unbalanced Releases are perfectly acceptable. it ** will merely cause the runtime to create a new ** stringbuilder next time Acquire is called. * *** GetStringAndRelease **-ToString () the stringbuilder, release it to the ** cache and return the resulting string ** ======================== ======================================================= */using transaction E M. threading; namespace System. text {internal static class StringBuilderCache {// The value 360 was chosen in discussion with performance experts as a compromise between using // as litle memory (per thread) as possible and still covering a large part of short-lived // StringBuilder creations on the startup path of VS designers. private const int MAX_BUILDER_SIZE = 360; [ThreadStatic] private stat Ic StringBuilder CachedInstance; public static StringBuilder Acquire (int capacity = StringBuilder. DefaultCapacity) {if (capacity <= MAX_BUILDER_SIZE) {StringBuilder sb = StringBuilderCache. CachedInstance; if (sb! = Null) {// Avoid stringbuilder block fragmentation by getting a new StringBuilder // when the requested size is larger than the current capacity if (capacity <= sb. capacity) {StringBuilderCache. cachedInstance = null; sb. clear (); return sb ;}}return new StringBuilder (capacity);} public static void Release (StringBuilder sb) {if (sb. capacity <= MAX_BUILDER_SIZE) {StringBuilderCache. cachedInst Ance = sb ;}} public static string GetStringAndRelease (StringBuilder sb) {string result = sb. toString (); Release (sb); return result ;}} the StringBuilder creation and string acquisition operations are cached here. The comments of the Code are clear, so I won't talk about it more here.. NET Source code can be viewed directly. You can use Reflector to view the Source code. Now, the Reference Source website can view the Source code online and detailed comment information, it is helpful to see how the Code improves itself.