标签:des style blog http color 使用
在开发中,有时候会遇到需要把一个List对象中的某个字段用一个分隔符拼成一个字符串的情况。比如在SQL语句的in条件中,我们通常需要把List<int>这样的对象转换为“1,2,3”这样的字符串,然后作为in的语句传进去。所以自然而然,可以通过循环的方式来拼着个字符串,于是可以写一个下面这样的通用方法:
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().TrimEnd(seperator); return result; }
方法其实很简单,首先创建一个StringBuilder,然后再往里面Append数据,最后把最后多余的最后一个分隔符去除。
后来发现BCL中string类型提供了现成的string.Join方法,该方法的功能和上面的方法相同。于是很好奇,想看看BCL中是如何实现这么一个简单的功能的,由于BCL的大部分代码已经开源,您可以使用Reflector这个工具查看,我之前就是使用这个工具,但是最近看到了微软的Reference Source 这个网站,可以在线查看源代码,比如string类的实现如下,您可以看到诸如string的GetHashCode是如何实现的等等, 这里我们回到我们想要查看的Join方法上来,其实现如下:
[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); } }
代码是不是很简单。对比之前手动实现的方法,发现自己写的代码看起来很挫,这个就是差距,String的Join方法中我们可以看到一下几个地方值得注意:
这个类一看就是对StringBuilder的缓存,因为对于一些小的字符串,创建StringBuilder也是一笔开销。StringBuilder的实现如下:
// ==++== // // 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 the ** number of instances constructed and collected. ** ** Acquire - is used to get a string builder to use of a ** particular 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 calls will 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. ** The stringbuilder should 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 System.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 static 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.CachedInstance = sb; } } public static string GetStringAndRelease(StringBuilder sb) { string result = sb.ToString(); Release(sb); return result; } } }
这里面对StringBuilder的创建和字符串获取进行了缓存。 代码的注释很清楚,这里就不多讲了。
.NET的源代码大部分都可以直接看了,以前可以使用Reflector进行查看,现在Reference Source 这个网站可以在线查看源代码以及详细的注释信息,看看代码对自己的提高还是挺有帮助的。
BCL中String.Join的实现,布布扣,bubuko.com
标签:des style blog http color 使用
原文地址:http://www.cnblogs.com/yangecnu/p/Join-method-implement-in-DotNet-BCL.html