有段时间没写博客了,不过我还是没有放松学习DotNet,这几天一直在看《.Net 框架程序设计》,收获很大!这本书不愧为.Net领域里的圣经,写得太好了,运思精深、鞭辟入里。我这是看的第一遍,而且才看了三分之一,就对.Net有了更深的理解,真的有一种豁然开朗的感觉,原来的很多问题,看了后才明白,原来就是这么回事呀。好东西不敢独享,接下来的几天我会在博客里把我的收获都写出来,和大家分享。
看这个类
{
private int age = 22;
}
C#提供了一种简便的方法让我们初始化字段,如果我们用ildasm.exe查看这个类的构造函数IL代码,会发现C#把这行代码内联到了无参构造函数中,这样的确很方便,但却带来了一个我们不得不需要引起重视的问题。
看下面的代码
{
private int age = 22;
private string name = "chengbo";
public MyClass() {
}
public MyClass(int age) {
this.name = "cb";
}
}
这个类提供了两个公有构造函数,其中第二个构造函数的IL如下
instance void .ctor(int32 age) cil managed
{
// Code size 37 (0x25)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldc.i4.s 22
IL_0003: stfld int32 Chengbo.MyClass::age
IL_0008: ldarg.0
IL_0009: ldstr "chengbo"
IL_000e: stfld string Chengbo.MyClass::name
IL_0013: ldarg.0
IL_0014: call instance void [mscorlib]System.Object::.ctor()
IL_0019: ldarg.0
IL_001a: ldstr "cb"
IL_001f: stfld string Chengbo.MyClass::name
IL_0024: ret
} // end of method MyClass::.ctor
可以看出,他首先内联了两个私有字段的代码,跟着调用了基类(System.Object类)的构造函数,再把cb赋值给name字段。
再看第一个,也就是那个无参的构造函数的IL
instance void .ctor() cil managed
{
// Code size 26 (0x1a)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldc.i4.s 22
IL_0003: stfld int32 Chengbo.MyClass::age
IL_0008: ldarg.0
IL_0009: ldstr "chengbo"
IL_000e: stfld string Chengbo.MyClass::name
IL_0013: ldarg.0
IL_0014: call instance void [mscorlib]System.Object::.ctor()
IL_0019: ret
} // end of method MyClass::.ctor
同样,他也内联了两个私有字段的代码,跟着调用了基类(System.Object类)的构造函数。
这样,两个构造函数都内联了私有字段的赋值代码,无疑是增加了整个代码的长度,也就是所谓的“代码膨胀效应”。
那么应该怎么解决呢?可以像下面这样
{
private int age;
private string name;
public MyClass()
{
age = 22;
name = "chengbo";
}
public MyClass(int age) : this()
{
this.name = "cb";
}
}
第二个构造函数显式调用了第一个(无参)构造函数,然后再把cb赋值给name字段
看看他的IL
instance void .ctor(int32 age) cil managed
{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: call instance void Chengbo.MyClass::.ctor()
IL_0006: ldarg.0
IL_0007: ldstr "cb"
IL_000c: stfld string Chengbo.MyClass::name
IL_0011: ret
} // end of method MyClass::.ctor
只是调用了第一个(无参的)构造函数,然后再把cb赋值给name字段,并没有内联私有字段赋值代码。
引用Jaffrey Richter在《Applied Microsoft .Net Framework Programming》中的一段话:
If you have several initialized instance fields and a lot of overloaded constructor methods, you should consider defining the fields without the initialization, creating a single constructor that performs the common initialization, and having each constructor explicitly call the common initialization constructor.This approach will reduce the size of the generated code.