共计 2984 个字符,预计需要花费 8 分钟才能阅读完成。
1. 老版本的代码
1 internal class Person | |
2 {3 public string Name { get; set;} | |
4 public int Age {get; set;} | |
5 | |
6 public override string ToString() | |
7 {8 return string.Format("[name={0},age={1}]", Name, Age); | |
9 } | |
10 } |
通常我们在格式化字符串的时候会使用 string 的静态方法 Format 来进行字符串拼接,然后使用 {0}…{n} 来充当占位符。如果 {n} 过大,代码的可读性就会急剧下降,C#6 引入一个新语法来简化这种书写方式。
2. $”{xxx:}”
我们之间来看新语法:
1 internal class Person | |
2 {3 public string Name { get; set;} | |
4 public int Age {get; set;} | |
5 | |
6 public override string ToString() | |
7 {8 return $"[name={Name},age={Age}]"; | |
9 } | |
10 } |
新语法采用 $ 开头,然后把之前的 {n} 换成了有意义的表达式,直观且简洁,且在 VS2015 中会有智能提示。好了,基本用法就是这样,按老习惯,对比下 IL 代码吧。
老版本的 IL:
1 .method public hidebysig virtual instance string | |
2 ToString() cil managed | |
3 {4 // Code size 33 (0x21) | |
5 .maxstack 3 | |
6 .locals init ([0] string V_0) | |
7 IL_0000: nop | |
8 IL_0001: ldstr "[name={0},age={1}]" | |
9 IL_0006: ldarg.0 | |
10 IL_0007: call instance string csharp6.Person::get_Name() | |
11 IL_000c: ldarg.0 | |
12 IL_000d: call instance int32 csharp6.Person::get_Age() | |
13 IL_0012: box [mscorlib]System.Int32 | |
14 IL_0017: call string [mscorlib]System.String::Format(string, | |
15 object, | |
16 object) | |
17 IL_001c: stloc.0 | |
18 IL_001d: br.s IL_001f | |
19 IL_001f: ldloc.0 | |
20 IL_0020: ret | |
21 } // end of method Person::ToString |
新语法的 IL:
1 .method public hidebysig virtual instance string | |
2 ToString() cil managed | |
3 {4 // Code size 33 (0x21) | |
5 .maxstack 3 | |
6 .locals init ([0] string V_0) | |
7 IL_0000: nop | |
8 IL_0001: ldstr "[name={0},age={1}]" | |
9 IL_0006: ldarg.0 | |
10 IL_0007: call instance string csharp6.Person::get_Name() | |
11 IL_000c: ldarg.0 | |
12 IL_000d: call instance int32 csharp6.Person::get_Age() | |
13 IL_0012: box [mscorlib]System.Int32 | |
14 IL_0017: call string [mscorlib]System.String::Format(string, | |
15 object, | |
16 object) | |
17 IL_001c: stloc.0 | |
18 IL_001d: br.s IL_001f | |
19 IL_001f: ldloc.0 | |
20 IL_0020: ret | |
21 } // end of method Person::ToString |
第一眼看到新版本的 IL 代码,我还以为我没有重新编译我的代码。C# 编译器帮我们转成了老版本的写法而已,一模一样的。。。so, 这又是一个语法层面的优化。
3. Example
1 // 支持方法调用 | |
2 string s1 = $"{person.GetHashCode()}"; | |
3 // 支持表达式 | |
4 string s2 = $"person.{nameof(person.Name)} is {person?.Name}"; | |
5 // 支持格式化输出 | |
6 DateTime now = DateTime.Now; | |
7 string s3 = $"DateTime.Now={now:yyyy-MM-dd HH:mm:ss}"; | |
8 // 组合表达式和格式化输出 | |
9 string s4 = $"{person.Name,2} is {person.Age:D2} year{(person.Age == 1 ?"" : "s")} old."; | |
10 // 支持的隐式类型转换 | |
11 IFormattable s5 = $"Hello, {person.Name}"; | |
12 FormattableString s6 = $"Hello, {person.Name}" |
新语法支持表达式求值,支持: 格式化操作,还支持到 IFormattable 的隐式转换,编译结果是利用 System.Runtime.CompilerServices.FormattableStringFactory.Create 这个静态方法构造一个 FormattableString 实现的。IL 如下:
1 IL_0095: stloc.s s4 | |
2 IL_0097: ldstr "Hello, {0}" | |
3 IL_009c: ldc.i4.1 | |
4 IL_009d: newarr[mscorlib] System.Object | |
5 IL_00a2: dup | |
6 IL_00a3: ldc.i4.0 | |
7 IL_00a4: ldloc.0 | |
8 IL_00a5: callvirt instance string csharp6.Person::get_Name() | |
9 IL_00aa: stelem.ref | |
10 IL_00ab: call class [mscorlib]System.FormattableString[mscorlib] System.Runtime.CompilerServices.FormattableStringFactory::Create(string,object[]) | |
13 IL_00b0: stloc.s s5 | |
14 IL_00b2: ldstr "Hello, {0}" | |
15 IL_00b7: ldc.i4.1 | |
16 IL_00b8: newarr[mscorlib] System.Object | |
17 IL_00bd: dup | |
18 IL_00be: ldc.i4.0 | |
19 IL_00bf: ldloc.0 | |
20 IL_00c0: callvirt instance string csharp6.Person::get_Name() | |
21 IL_00c5: stelem.ref | |
22 IL_00c6: call class [mscorlib]System.FormattableString[mscorlib] System.Runtime.CompilerServices.FormattableStringFactory::Create(string,object[]) |
正文完
星哥玩云-微信公众号
