《CLR Via C# 第3版》笔记之(十六) - 字符串
.Net中的字符串是被谈论最多的话题,这里也进行一些总结,供以后参考。
主要内容:
- 字符串的不可变性和字符串留用
- 语言文化
- 格式化器
1. 字符串的不可变性和字符串留用
字符串(string)在.Net中是一个特殊的类。
.Net中的字符串是不可变的(immutable)。也就是说,字符串已经创建就不能更改,变长,变短,修改字符都不行。
对字符串进行的任何操作都不能改变原字符串,只会生成新的字符串。
由于String是不可变的,我们在使用大量的字符串拼接的时候不宜使用 【+】运算符,比如
1 | "A" + "B" + "C" |
而是可以使用StringBuilder这个类,
1 2 3 4 | StringBuilder sb = new StringBuilder(); sb.Append( "A" ); sb.Append( "B" ); sb.Append( "C" ); |
这样可以避免在内存中不断生成新的string对象。
StringBuilder的工作原理大致是这样的:
内部维护一个字符数组,并且有一个初始容量。
新的字符串都加入到这个数组中。
当加入的字符超过容量时,就重新new一个更大的数组,并将原先的数组内容拷入新数组中。
将原有的数组进行垃圾回收,新的字符串加入到使用新的字符数组中。
StringBuilder的ToString方法见字符数组转换为一个String输出。
为了提高字符串的性能,.Net中对已有的字符串进行了留用,使得再次使用相同的字符串时不用重新申请内存。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | using System; public class CLRviaCSharp_16 { static void Main( string [] args) { string s1 = "Hello" ; string s2 = "Hello" ; // 应该为 False Console.WriteLine( object .ReferenceEquals(s1, s2)); s1 = String.Intern( "Hello" ); s2 = String.Intern( "Hello" ); // 显示 True Console.WriteLine( object .ReferenceEquals(s1, s2)); Console.ReadKey( true ); } } |
第一次的执行结果应该为False,但是CLR在编译时默认进行了留用,所以2次结果都是True
我们如果要使用字符串留用的话,一定要明确使用String.Intern,否则CLR版本变更后有可能不默认进行字符串留用。
那样,运行结果就变了。
2. 语言文化
字符串的语言文化在使用中很少涉及,但是如果不注意的话,可能会遇到意料之外的错误。
如以下中文和日语的比较,用不同的语言文化,比较结果就不同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | using System; using System.Globalization; public class CLRviaCSharp_16 { static void Main( string [] args) { string s1 = "中文" ; string s2 = "日本語" ; CompareInfo compareInfo = CompareInfo.GetCompareInfo( "ja-JP" ); Console.WriteLine(compareInfo.Compare(s1, s2)); compareInfo = CompareInfo.GetCompareInfo( "zh-CN" ); Console.WriteLine(compareInfo.Compare(s1, s2)); Console.ReadKey( true ); } } |
在不同语言之间进行字符串比较需要注意语言文化对结果的影响。
3. 格式化器
通过格式化器,可以将字符串按照一定的格式输出,在打印或者log输出上会很有用。
实现自定义的格式化器需要继承IFormatProvider, ICustomFormatter两个接口。
下面通过例子演示如何通过定制格式化器来调整打印输出的。
例子很简单,依次输出字符串,
如果字符串长度大于4,则截断尾部,只输出4个字符。
如果字符串长度小于4,则在尾部补充【*】,使长度达到4。
如果字符串长度等于4,则直接输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | using System; public class CLRviaCSharp_16 { static void Main( string [] args) { string [] strs = new string [] { "sadfasdf" , "dgdgfdsds" , "ggh" , "w" , "abcd" }; foreach ( var str in strs) { Console.WriteLine( string .Format( new FormatPrint(), "{0}" , str)); } Console.ReadKey( true ); } } internal class FormatPrint : IFormatProvider, ICustomFormatter { #region IFormatProvider Members public object GetFormat(Type formatType) { if (formatType == typeof (ICustomFormatter)) return this ; else return null ; } #endregion #region ICustomFormatter Members public string Format( string format, object arg, IFormatProvider formatProvider) { string s; IFormattable formattable = arg as IFormattable; if (formattable == null ) s = arg.ToString(); else s = formattable.ToString(format, formatProvider); // 开始处理长度 if (s.Length > 4) return s.Substring(0, 4); else if (s.Length == 4) return s; for ( int i = s.Length; i < 4; i++) s += "*" ; return s; } #endregion } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!