本章主要讲了 名字是方法,却主要讲了构造器
实例构造器,静态构造器,在结构和类中的区别
生成了一样的代码,就算你不写构造器,编译器也默认生成一个
1 public class ClassTest 2 { 3 public ClassTest() 4 : base() 5 { 6 7 } 8 }
public class ClassTest { }
1 // 代码大小 7 (0x7) 2 .maxstack 8 3 IL_0000: ldarg.0 4 IL_0001: call instance void [mscorlib]System.Object::.ctor() 5 IL_0006: ret
调用顺序.
1 public class ClassTest 2 { 3 4 public int a; 5 public int b = 5; 6 7 public ClassTest() 8 : base() 9 { 10 a = 2; 11 b = 4; 12 } 13 }
// 代码大小 28 (0x1c) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldc.i4.5 IL_0002: stfld int32 EFTest.ClassTest::b IL_0007: ldarg.0 IL_0008: call instance void [mscorlib]System.Object::.ctor() IL_000d: ldarg.0 IL_000e: ldc.i4.2 IL_000f: stfld int32 EFTest.ClassTest::a IL_0014: ldarg.0 IL_0015: ldc.i4.4 IL_0016: stfld int32 EFTest.ClassTest::b IL_001b: ret
先赋值.
然后在实例构造. 然后再赋值.
如果不没赋值,编译器会赋默认值,引用类型 NULL,值类型0.
值类型构造器
首先结构不允许 参数为空的构造器。编译器也不会创建默认构造器
1 public struct ClassTest1 2 { //错误 1 结构不能包含显式的无参数构造函数 3 public ClassTest1() 4 { 5 6 } 7 }
在没有显示声明的构造器的情况下也编译器也不会声明
1 public struct ClassTest1 2 { 3 4 }
调用的顺序和 CLass一样 。同样没有初始化 总是被初始化为0或null
结构不允许默认构造函数。
结构中不能有实例字段初始值设定项.
1 private Int32 m_x = 5;
包括构造函数必须所有参数都赋值,不能部分赋值
1 public struct ClassTest1 2 { 3 private Int32 m_x ; 4 private Int32 m_y ; 5 6 public ClassTest1(int x) 7 { 8 m_x = x; 9 } 10 }
错误 1 在控制返回到调用方之前,字段“EFTest.ClassTest1.m_y”必须完全赋值
这些让我没有明白.
书中的说法是 "生成可验证的代码" 完全没有明白. 毕竟你完全可以这样
1 public struct ClassTest1 2 { 3 private Int32 m_x ; 4 private Int32 m_y ; 5 } 6 7 var o = new ClassTest1(); 8 Console.WriteLine(o.m_x);
然后输出为 0 这不也赋值了吗? 为什么就不能不分赋值.
不允许无参构造和内联赋值.也不是特别明白.
这种不知道的感觉特别蛋疼
静态构造器
首先静态构造器相当于一个私有且无参的实例构造
1 struct ClassTest1 2 { 3 Int32 m_x ; 4 Int32 m_y ; 5 6 static ClassTest1() 7 { 8 9 } 10 }
1 public class ClassTest2 2 { 3 public static int staticcount = 0; 4 public static int count = 0; 5 static ClassTest2() 6 { 7 staticcount++; 8 Console.WriteLine(" 静态构造调用 " + staticcount + "次"); 9 } 10 11 public ClassTest2() 12 { 13 count++; 14 Console.WriteLine(" 构造调用 " + count + "次"); 15 } 16 }
1 var o = new ClassTest2(); 2 var o1 = new ClassTest2(); 3 var o2 = new ClassTest2(); 4 Console.WriteLine(o1.GetType()); 5 Console.WriteLine(o2.GetType()); 6 Console.WriteLine(o2.GetType());
静态构造只调用了一次,而普通构造函数却能够每次初始化都调用.
上图也说明了调用顺序问题
此外,静态构造函数也只是由 CLR调用. 开发人员是无法调用的
关于性能损耗.
1 public sealed class TypeConstructorPerformance 2 { 3 public static void Go() 4 { 5 const Int32 iterations = 1000 * 1000 * 1000; 6 PerfTest1(iterations); 7 PerfTest2(iterations); 8 } 9 10 internal sealed class BeforeFieldInit 11 { 12 public static Int32 s_x = 123; 13 } 14 15 internal sealed class Precise 16 { 17 public static Int32 s_x; 18 static Precise() { s_x = 123; } 19 } 20 21 private static void PerfTest1(Int32 iterations) 22 { 23 Stopwatch sw = Stopwatch.StartNew(); 24 for (Int32 x = 0; x < iterations; x++) 25 { 26 BeforeFieldInit.s_x = 1; 27 } 28 Console.WriteLine("PerfTest1: {0} BeforeFieldInit", sw.Elapsed); 29 30 sw = Stopwatch.StartNew(); 31 for (Int32 x = 0; x < iterations; x++) 32 { 33 Precise.s_x = 1; 34 } 35 Console.WriteLine("PerfTest1: {0} Precise", sw.Elapsed); 36 } 37 38 private static void PerfTest2(Int32 iterations) 39 { 40 Stopwatch sw = Stopwatch.StartNew(); 41 for (Int32 x = 0; x < iterations; x++) 42 { 43 BeforeFieldInit.s_x = 1; 44 } 45 Console.WriteLine("PerfTest2: {0} BeforeFieldInit", sw.Elapsed); 46 47 sw = Stopwatch.StartNew(); 48 for (Int32 x = 0; x < iterations; x++) 49 { 50 Precise.s_x = 1; 51 } 52 Console.WriteLine("PerfTest2: {0} Precise", sw.Elapsed); 53 } 54 }
这是书中一个例子
同样的例子 我和书中得出的结果是不一样的. 不知道是不是CPU进化的结果导致的.
直接内联构造和静态构造 性能还是有些差别的。
不过这种调用次数这种差别。 我觉得可以忽略了...
接下来就是一些操作符以及自己写语法糖的介绍, 比较简单,贴一下代码就可以了
操作符重载
1 internal sealed class Complex 2 { 3 public Int32 a; 4 5 public Complex(Int32 c) 6 { 7 a = c; 8 } 9 10 public static Complex operator%(Complex c1,Complex c2) 11 { 12 var c3 = new Complex(c1.a + c2.a); 13 14 return c3; 15 } 16 }
1 .method public hidebysig specialname static 2 class EFTest.Complex op_Modulus(class EFTest.Complex c1, 3 class EFTest.Complex c2) cil managed 4 { 5 // 代码大小 21 (0x15) 6 .maxstack 2 7 .locals init ([0] class EFTest.Complex c3) 8 IL_0000: ldarg.0 9 IL_0001: ldfld int32 EFTest.Complex::a 10 IL_0006: ldarg.1 11 IL_0007: ldfld int32 EFTest.Complex::a 12 IL_000c: add 13 IL_000d: newobj instance void EFTest.Complex::.ctor(int32) 14 IL_0012: stloc.0 15 IL_0013: ldloc.0 16 IL_0014: ret 17 } // end of method Complex::op_Modulus
1 var c1 = new Complex(1); 2 var c2 = new Complex(2); 3 Console.WriteLine((c1 % c2).a);
IL_0000: ldc.i4.1 IL_0001: newobj instance void EFTest.Complex::.ctor(int32) IL_0006: stloc.0 IL_0007: ldc.i4.2 IL_0008: newobj instance void EFTest.Complex::.ctor(int32) IL_000d: stloc.1 IL_000e: ldloc.0 IL_000f: ldloc.1 IL_0010: call class EFTest.Complex EFTest.Complex::op_Modulus(class EFTest.Complex, class EFTest.Complex)
具体有哪些操作.
转换操作符方法
1 public sealed class Rational 2 { 3 public Rational(Int32 num) 4 { 5 Console.WriteLine(num); 6 } 7 8 public static implicit operator Rational(Int32 num) 9 { 10 return new Rational(num); 11 } 12 }
Rational r1 = 1;
当然他也有反过来的操作 explicit.
扩展方法
1 public static class StringExtensions 2 { 3 public static Int32 ToFuck(this String c) 4 { 5 if (c == null) 6 return -1; 7 8 return c.Length * 15; 9 } 10 }
有点儿像 js 中更改原形一样.
默认返回一个自身.
以上这些方法都是让你语法更加简洁。
理论上不用这些都是可以用其他方法弄出来。
end