编程点滴,目前主要研究Android

对待生活,应该怀着一颗感恩的心

首页 新随笔 联系 订阅 管理

有段时间没写博客了,不过我还是没有放松学习DotNet,这几天一直在看《.Net 框架程序设计》,收获很大!这本书不愧为.Net领域里的圣经,写得太好了,运思精深、鞭辟入里。我这是看的第一遍,而且才看了三分之一,就对.Net有了更深的理解,真的有一种豁然开朗的感觉,原来的很多问题,看了后才明白,原来就是这么回事呀。好东西不敢独享,接下来的几天我会在博客里把我的收获都写出来,和大家分享。

看这个类

class MyClass
{
    
private int age = 22;
}

C#提供了一种简便的方法让我们初始化字段,如果我们用ildasm.exe查看这个类的构造函数IL代码,会发现C#把这行代码内联到了无参构造函数中,这样的确很方便,但却带来了一个我们不得不需要引起重视的问题。

看下面的代码

class MyClass
{
    
private int age = 22;
    
private string name = "chengbo";

    
public MyClass() {
    }


    
public MyClass(int age) {
        
this.name = "cb";
    }

}

这个类提供了两个公有构造函数,其中第二个构造函数的IL如下

.method public hidebysig specialname rtspecialname 
        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

.method public hidebysig specialname rtspecialname 
        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类)的构造函数。
这样,两个构造函数都内联了私有字段的赋值代码,无疑是增加了整个代码的长度,也就是所谓的“代码膨胀效应”。
那么应该怎么解决呢?可以像下面这样

class MyClass
{
    
private int age;
    
private string name;

    
public MyClass() 
    
{
        age 
= 22;
        name 
= "chengbo";
    }


    
public MyClass(int age) : this()
    
{
        
this.name = "cb";
    }

}

第二个构造函数显式调用了第一个(无参)构造函数,然后再把cb赋值给name字段
看看他的IL

.method public hidebysig specialname rtspecialname 
        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.

posted on 2005-04-09 16:10  chengbo  阅读(592)  评论(0编辑  收藏  举报