您的位置:首页 > 编程语言

警惕当类中有多个构造函数时的代码膨胀效应

2005-10-31 11:29 519 查看
有段时间没写博客了,不过我还是没有放松学习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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息