警惕当类中有多个构造函数时的代码膨胀效应
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.
看这个类
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.
相关文章推荐
- 警惕当类中有多个构造函数时的代码膨胀效应
- C# 构造函数避免IL(反编译)代码膨胀的方法--C#编译有点狂啊
- 黑马程序员_对象,构造函数以及构造代码块
- nc7下某个用户某个节点有多个模板,可以通过代码实现通过选择不同的业务流程来调用不同的模板吗?
- js根据手机客户端浏览器类型,判断跳转pc/手机网站多个实例代码
- 泛型就意味着代码膨胀?
- 同一套代码部署多个实例来并行完成某项任务,且避免重复执行
- 面试题:(考察构造函数、对象、实例函数、代码执行顺序等知识点)
- java 上传文件代码,支持中文文件名和中文文件内容,可以同时提交多个参数
- 代码重构警惕陷入“过度适应”陷阱
- 代码疑云(7)-构造函数在类继承时
- 编写一段代码,演示多个字符从两端移动,向中间汇聚
- 判断多个input type=file是否有已经选择好文件的代码
- static静态代码块与非静态代码块 + 构造函数
- keil中对struct结构体静态赋值导致代码急剧膨胀的原因(转)
- 代码膨胀
- JavaScript中使用构造函数实现继承的代码
- 警惕javascript代码中的“</script>”!
- 防止模板代码膨胀
- 编写代码,演示多个字符从两端移动,向中间汇聚。