在开发中,有时候会遇到需要把一个List对象中的某个字段用一个分隔符拼成一个字符串的情况。比如在SQL语句的in条件中,我们通常需要把List<int>这样的对象转换为“1,2,3”这样的字符串,然后作为in的语句传进去。所以自然而然,可以通过循环的方式来拼着个字符串,于是可以写一个下面这样的通用方法:

  1. private static string GetStringFromList<T>(char seperator, IEnumerable<T> values)
  2. {
  3. if (seperator == null)
  4. return string.Empty;
  5.  
  6. if (values == null || values.Count() == 0)
  7. throw new ArgumentNullException("values");
  1. String result;
  2. StringBuilder strBuilder;
  3.  
  4. strBuilder = new StringBuilder();
  5. foreach (T str in values)
  6. {
  7. strBuilder.Append(str.ToString());
  8. strBuilder.Append(seperator);
  9. }
  10.  
  11. result = strBuilder.ToString().TrimEnd(seperator);
  12.  
  13. return result;
  14. }

方法其实很简单,首先创建一个StringBuilder,然后再往里面Append数据,最后把最后多余的最后一个分隔符去除。

后来发现BCL中string类型提供了现成的string.Join方法,该方法的功能和上面的方法相同。于是很好奇,想看看BCL中是如何实现这么一个简单的功能的,由于BCL的大部分代码已经开源,您可以使用Reflector这个工具查看,我之前就是使用这个工具,但是最近看到了微软的Reference Source 这个网站,可以在线查看源代码,比如string类的实现如下,您可以看到诸如string的GetHashCode是如何实现的等等, 这里我们回到我们想要查看的Join方法上来,其实现如下:

  1. [ComVisible(false)]
  2. public static String Join<T>(String separator, IEnumerable<T> values)
  3. {
  4. if (values == null)
  5. throw new ArgumentNullException("values");
  6. Contract.Ensures(Contract.Result<String>() != null);
  7. Contract.EndContractBlock();
  8.  
  9. if (separator == null)
  10. separator = String.Empty;
  11.  
  12. using (IEnumerator<T> en = values.GetEnumerator())
  13. {
  14. if (!en.MoveNext())
  15. return String.Empty;
  16.  
  17. StringBuilder result = StringBuilderCache.Acquire();
  18. if (en.Current != null)
  19. {
  20. // handle the case that the enumeration has null entries
  21. // and the case where their ToString() override is broken
  22. string value = en.Current.ToString();
  23. if (value != null)
  24. result.Append(value);
  25. }
  26.  
  27. while (en.MoveNext())
  28. {
  29. result.Append(separator);
  30. if (en.Current != null)
  31. {
  32. // handle the case that the enumeration has null entries
  33. // and the case where their ToString() override is broken
  34. string value = en.Current.ToString();
  35. if (value != null)
  36. result.Append(value);
  37. }
  38. }
  39. return StringBuilderCache.GetStringAndRelease(result);
  40. }
  41. }

代码是不是很简单。对比之前手动实现的方法,发现自己写的代码看起来很挫,这个就是差距,String的Join方法中我们可以看到一下几个地方值得注意:

  1. 在方法的开始处,使用了Contract 这个类来进行验证协助代码的编写,这个在之前的文章中有所介绍,这里使用了后置条件判断,表示方法的返回值需要是string类型,并且不为空;还有就是在方法开始处做必要的参数合法性验证;在方法中及时判断,及时返回。
  2. 在实现中,使用了枚举器,C#中的foreach语句其实就是这种枚举器的语法糖,所以这里没有什么好说的,值得一提的是在while循环中的判断语句while(en.MoveNext) 很好的避免了我们方法中在字符串末尾添加多余的字符串,最后还要调用TrimEnd的这种无谓的内存开销。这其实也是do{…}while(..),和while(…){…}这两种循环体的差异体现。
  3. 实现中,没有直接new直接分配StringBuilder,在返回字符串时也没有直接使用ToString方法,而是使用了StringBuilderCache这个类,这个在之前翻译的.NET程序的性能要领和优化建议 这篇文章中有所介绍。

这个类一看就是对StringBuilder的缓存,因为对于一些小的字符串,创建StringBuilder也是一笔开销。StringBuilder的实现如下:

  1. // ==++==
  2. //
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. //
  5. // ==--==
  6. /*============================================================
  7. **
  8. ** Class: StringBuilderCache
  9. **
  10. ** Purpose: provide a cached reusable instance of stringbuilder
  11. ** per thread it's an optimisation that reduces the
  12. ** number of instances constructed and collected.
  13. **
  14. ** Acquire - is used to get a string builder to use of a
  15. ** particular size. It can be called any number of
  16. ** times, if a stringbuilder is in the cache then
  17. ** it will be returned and the cache emptied.
  18. ** subsequent calls will return a new stringbuilder.
  19. **
  20. ** A StringBuilder instance is cached in
  21. ** Thread Local Storage and so there is one per thread
  22. **
  23. ** Release - Place the specified builder in the cache if it is
  24. ** not too big.
  25. ** The stringbuilder should not be used after it has
  26. ** been released.
  27. ** Unbalanced Releases are perfectly acceptable. It
  28. ** will merely cause the runtime to create a new
  29. ** stringbuilder next time Acquire is called.
  30. **
  31. ** GetStringAndRelease
  32. ** - ToString() the stringbuilder, Release it to the
  33. ** cache and return the resulting string
  34. **
  35. ===========================================================*/
  36. using System.Threading;
  37.  
  38. namespace System.Text
  39. {
  40. internal static class StringBuilderCache
  41. {
  42. // The value 360 was chosen in discussion with performance experts as a compromise between using
  43. // as litle memory (per thread) as possible and still covering a large part of short-lived
  44. // StringBuilder creations on the startup path of VS designers.
  45. private const int MAX_BUILDER_SIZE = 360;
  46.  
  47. [ThreadStatic]
  48. private static StringBuilder CachedInstance;
  49.  
  50. public static StringBuilder Acquire(int capacity = StringBuilder.DefaultCapacity)
  51. {
  52. if(capacity <= MAX_BUILDER_SIZE)
  53. {
  54. StringBuilder sb = StringBuilderCache.CachedInstance;
  55. if (sb != null)
  56. {
  57. // Avoid stringbuilder block fragmentation by getting a new StringBuilder
  58. // when the requested size is larger than the current capacity
  59. if(capacity <= sb.Capacity)
  60. {
  61. StringBuilderCache.CachedInstance = null;
  62. sb.Clear();
  63. return sb;
  64. }
  65. }
  66. }
  67. return new StringBuilder(capacity);
  68. }
  69.  
  70. public static void Release(StringBuilder sb)
  71. {
  72. if (sb.Capacity <= MAX_BUILDER_SIZE)
  73. {
  74. StringBuilderCache.CachedInstance = sb;
  75. }
  76. }
  77.  
  78. public static string GetStringAndRelease(StringBuilder sb)
  79. {
  80. string result = sb.ToString();
  81. Release(sb);
  82. return result;
  83. }
  84. }
  85. }

这里面对StringBuilder的创建和字符串获取进行了缓存。 代码的注释很清楚,这里就不多讲了。

.NET的源代码大部分都可以直接看了,以前可以使用Reflector进行查看,现在Reference Source 这个网站可以在线查看源代码以及详细的注释信息,看看代码对自己的提高还是挺有帮助的。

BCL中String.Join的实现的更多相关文章

  1. C# 中String.Join()方法

    今天在工作中看到了组里一个大佬写的代码,感触颇多,同样实现一个需求,我写循环费了老大劲,代码又臭又长,大佬的代码简洁明了,三行搞定...不得不说,今天赚大了 简单总结一下今天赚到的知识 string里 ...

  2. Java8中String.join方法

    List names=new ArrayList<String>(); names.add("1"); names.add("2"); names. ...

  3. String.Join的实现

    String.Join的实现 在开发中,有时候会遇到需要把一个List对象中的某个字段用一个分隔符拼成一个字符串的情况.比如在SQL语句的in条件中,我们通常需要把List<int>这样的 ...

  4. 【转载】 C#使用string.Join快速用特定字符串串联起数组

    在C#中有时候我们的数组元素需要通过一些特定的字符串串联起来,例如将整形Int数组通过逗号快速串联起来成为一个字符串,可以使用String.Join方法.或者一个字符串string类型数组所有元素快速 ...

  5. c# String.Join 和 Distinct 方法 去除字符串中重复字符

    1.在写程序中经常操作字符串,需要去重,以前我的用方式利用List集合和 contains去重复数据代码如下: string test="123,123,32,125,68,9565,432 ...

  6. String.Join 和 Distinct 方法 去除字符串中重复字符

    Qualys项目中写到将ServerIP以“,”分割后插入数据库并将重复的IP去除后发送到服务器进行Scan,于是我写了下面的一段用来剔除重复IP: //CR#1796870 modify by v- ...

  7. python3与python2中的string.join()函数

    在python2中,string 模块中有一个join()函数,用于以特定的分隔符分隔源变量中的字符串,将其作为新的元素加入到一个列表中,例如: body=string.join(( "Fr ...

  8. String.join() --Java8中String类新增方法

    序言 在看别人的代码时发现一个方法String.join(),因为之前没有见过所以比较好奇. 跟踪源码发现源码很给力,居然有用法示例,以下是源码: /** * Returns a new String ...

  9. Python中的join()函数的用法

    函数:string.join() Python中有join()和os.path.join()两个函数,具体作用如下:    join():    连接字符串数组.将字符串.元组.列表中的元素以指定的字 ...

随机推荐

  1. 【原】谈谈对Objective-C中代理模式的误解

    [原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...

  2. 漫扯:从polling到Websocket

    Http被设计成了一个单向的通信的协议,即客户端发起一个request,然后服务器回应一个response.这让服务器很为恼火:我特么才是老大,我居然不能给小弟发消息... 轮询 老大发火了,小弟们自 ...

  3. 【微框架】Maven +SpringBoot 集成 阿里大鱼 短信接口详解与Demo

    Maven+springboot+阿里大于短信验证服务 纠结点:Maven库没有sdk,需要解决 Maven打包找不到相关类,需要解决 ps:最近好久没有写点东西了,项目太紧,今天来一篇 一.本文简介 ...

  4. SQL Server-聚焦计算列或计算列持久化查询性能(二十二)

    前言 上一节我们详细讲解了计算列以及计算列持久化的问题,本节我们依然如前面讲解来看看二者查询性能问题,简短的内容,深入的理解,Always to review the basics. 持久化计算列比非 ...

  5. .net windows Kafka 安装与使用入门(入门笔记)

    完整解决方案请参考: Setting Up and Running Apache Kafka on Windows OS   在环境搭建过程中遇到两个问题,在这里先列出来,以方便查询: 1. \Jav ...

  6. UWP开发必备以及常用知识点总结

    一直在学UWP,一直在写Code,自己到达了什么水平?还有多少东西需要学习才能独挡一面?我想对刚接触UWP的开发者都有这种困惑,偶尔停下来总结分析一下还是很有收获的! 以下内容是自己开发中经常遇到的一 ...

  7. EC笔记:第4部分:20、传递引用代替传值

    考虑以下场景: #include <iostream> #include <string> using namespace std; struct Person { strin ...

  8. AFN解析器里的坑

    AFN框架是用来用来发送网络请求的,它的好处是可以自动给你解析JSON数据,还可以发送带参数的请求AFN框架还可以监测当前的网络状态,还支持HTTPS请求,分别对用的类为AFNetworkReacha ...

  9. 【初码干货】使用阿里云对Web开发中的资源文件进行CDN加速的深入研究和实践

    提示:阅读本文需提前了解的相关知识 1.阿里云(https://www.aliyun.com) 2.阿里云CDN(https://www.aliyun.com/product/cdn) 3.阿里云OS ...

  10. WebAPI

    WebAPI的Host OWIN IIS WebAPI 的handler和Filter有啥区别? WebAPI  常用 Filters Exception Filter Timer Filter Lo ...