BCL中String.Join的實現

來源:互聯網
上載者:User

標籤: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方法中我們可以看到一下幾個地方值得注意:

  1. 在方法的開始處,使用了Contract 這個類來進行驗證協助代碼的編寫,這個在之前的文章中有所介紹;還有就是在方法開始處做必要的參數合法性驗證;在方法中及時判斷,及時返回。
  2. 在實現中,使用了列舉程式,C#中的foreach語句其實就是這種列舉程式的文法糖,所以這裡沒有什麼好說的,值得一提的是在while迴圈中的判斷語句while(en.MoveNext) 很好的避免了我們方法中在字串末尾添加多餘的字串,最後還要調用TrimEnd的這種無謂的記憶體開銷。這其實也是do{…}while(..),和while(…){…}這兩種迴圈體的差異體現。
  3. 實現中,沒有直接new直接分配StringBuilder,在返回字串時也沒有直接使用ToString方法,而是使用了StringBuilderCache這個類,這個在之前翻譯的.NET程式的效能要領和最佳化建議 這篇文章中有所介紹。

這個類一看就是對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 這個網站可以線上查看原始碼以及詳細的注釋資訊,看看代碼對自己的提高還是挺有協助的。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.