上下文:c#中变量的内敛赋值其实是在构造函数中完成的,JIT会把变量的赋值语句放入每个构造函数开始的位置,因此,当类中有很多变量使用内联赋值,同时类也有多个构造函数的时候,实际编译生成的代码量会以乘法的方式叠加。比如一个类中有3个变量使用内联赋值,有4个构造函数,那么实际生成的赋值语句的数量将达到3x4=12句。
结论:尽量避免使用内联赋值,优先使用构造函数内赋值
类代码如下:
public class Cat
{
private string name;
public Cat()
{
}
public Cat(string _name)
{
name = _name;
}
public Cat(int _notuse)
{
name = "Hello Kitty";
}
public void Shout()
{
Console.WriteLine(name+" is now nyan nyan");
}
}
IL生成的代码如下:
//public Cat(string _name)
.method public hidebysig specialname rtspecialname
instance void .ctor(string _name) cil managed
{
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0//load argument 0,即,将this指针压栈
IL_0001: call instance void [mscorlib]System.Object::.ctor()//使用this并调用object构造函数
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0//将this指针压栈
IL_0009: ldarg.1//将_name压栈
IL_000a: stfld string DLLTest.Cat::name//将栈顶的值赋给name
IL_000f: nop
IL_0010: ret//返回
} // end of method Cat::.ctor
//public Cat(int _notuse)
.method public hidebysig specialname rtspecialname
instance void .ctor(int32 _notuse) cil managed
{
// Code size 21 (0x15)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0
IL_0009: ldstr "Hello Kitty”//将”Hello Kitty”压栈
IL_000e: stfld string DLLTest.Cat::name
IL_0013: nop
IL_0014: ret
} // end of method Cat::.ctor
//public Cat()
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 10 (0xa)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: nop
IL_0009: ret
} // end of method Cat::.ctor
从上面3个构造函数的IL代码可以看出,当变量不使用内联赋值的时候,构造函数内不会自行补充赋值语句
下面将贴上内联赋值的Cat
public class Cat
{
private string name="Hello Tom";
public Cat()
{
}
public Cat(string _name)
{
name = _name;
}
public Cat(int _notuse)
{
name = "Hello Kitty";
}
public void Shout()
{
Console.WriteLine(name+" is now nyan nyan");
}
}
其构造函数分别是:
.method public hidebysig specialname rtspecialname
instance void .ctor(string _name) cil managed
{
// Code size 28 (0x1c)
.maxstack 8
IL_0000: ldarg.0//this压栈
IL_0001: ldstr "Hello Tom”//将”Hello Tom”压栈
IL_0006: stfld string DLLTest.Cat::name//将”Hello Tom”赋值给this.name
IL_000b: ldarg.0
IL_000c: call instance void [mscorlib]System.Object::.ctor()
IL_0011: nop
IL_0012: nop
IL_0013: ldarg.0
IL_0014: ldarg.1
IL_0015: stfld string DLLTest.Cat::name
IL_001a: nop
IL_001b: ret
} // end of method Cat::.ctor
其他构造函数中同样会增加赋值的那三句
.method public hidebysig specialname rtspecialname
instance void .ctor(int32 _notuse) cil managed
{
// Code size 32 (0x20)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldstr "Hello Tom"
IL_0006: stfld string DLLTest.Cat::name
IL_000b: ldarg.0
IL_000c: call instance void [mscorlib]System.Object::.ctor()
IL_0011: nop
IL_0012: nop
IL_0013: ldarg.0
IL_0014: ldstr "Hello Kitty"
IL_0019: stfld string DLLTest.Cat::name
IL_001e: nop
IL_001f: ret
} // end of method Cat::.ctor
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 21 (0x15)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldstr "Hello Tom"
IL_0006: stfld string DLLTest.Cat::name
IL_000b: ldarg.0
IL_000c: call instance void [mscorlib]System.Object::.ctor()
IL_0011: nop
IL_0012: nop
IL_0013: nop
IL_0014: ret
} // end of method Cat::.ctor
相关推荐
赋值兼容规则和构造函数: 1. 赋值兼容规则只在公有继承下成立,基类对象可以赋值给派生类对象,但反之则不行。 2. 派生类构造函数需要初始化直接和间接基类,以及子对象。 3. 多重继承可能会导致二义性,解决...
然而,与类有所不同的是,结构体必须至少有一个无参数构造函数。这是因为值类型的默认初始化要求所有的字段都必须有一个初始值。 ```csharp public struct AddressBook { public string Name; public string ...
通过分析这道面试题,我们可以了解到C#实例化顺序的规则:首先调用静态构造函数,然后调用实例构造函数。同时,我们也需要了解内联方式初始化字段、类型构造器的执行时间和基类和子类实例化的顺序。只有通过深入的...
//运行时会抛出错误,因为 readonly 变量一旦初始化就不允许再次赋值 //Console.WriteLine("strReadOnly: {0}", Class1.strReadOnly); Console.ReadLine(); } }} 结果: strConst: Const 运行时会抛出错误:System....
44. **构造函数与析构函数**:构造函数用于初始化对象,而析构函数用于清理资源。 45. **成员函数与友元函数**:成员函数是类的一部分,而友元函数不是类的一部分,但可以访问类的私有成员。 46. **静态成员与实例...
- 构造函数的初始化列表:推荐使用初始化列表来初始化成员变量,而不是在构造函数体中赋值。 - 析构函数的虚函数性:确保基类的析构函数为虚函数,以支持多态删除派生类对象。 2. **内存管理** - 智能指针:利用...
- **构造函数**:初始化新对象时调用,有默认构造函数和自定义构造函数。 - **属性与字段**:属性用于安全地访问和修改对象的数据,字段是类中的私有数据存储。 3. **继承与多态** - **继承**:一个类可以从另一...
7. **使用readonly字段确保数据不可变**:readonly字段在构造函数之外不能被赋值,常用于实现线程安全的不变对象。 8. **理解并应用隐式线程局部变量**:在多线程环境中,隐式线程局部变量保证每个线程都有独立的...
- **构造函数** - 用于初始化新创建的对象。 - **属性** - 提供了一种访问类字段的方式,类似于方法调用。 - **索引器** - 允许类通过索引来访问其成员。 - **事件** - 一种特殊的委托类型,用于通知其他对象...
常量在编译时被内联,而readonly字段在运行时通过构造函数初始化。 3. extern是什么意思? extern关键字用于引入外部定义的函数或库,通常用于C/C++代码的互操作,例如调用操作系统API。 4. abstract是什么意思?...
理解何时使用移动构造函数和移动赋值运算符,而不是传统的拷贝构造函数和赋值运算符,能够减少不必要的资源复制,提高性能。 3. **STL容器的使用**:标准模板库(STL)提供了多种容器,如向量、列表、集合等。选择...
创建对象的方式包括字面量语法和构造函数。`this`关键字指向当前上下文,而`prototype`用于继承。 6. 数组: JavaScript的数组可以用方括号表示,支持方法如`push`、`pop`、`shift`、`unshift`、`slice`等。ES6...
定义类时,构造函数不是必需的,但可以提供默认行为。 24. 基于类的CSS样式前缀为".",基于ID的样式前缀为"#"。 25. CSS样式可以内联、在元素中或外部样式表中定义。 26. JavaScript代码通常包裹在标签内,用于在...
7. **常数据成员**:常数据成员(const data member)一旦在构造函数初始化列表中初始化,就不能再被修改。它们不能被一般成员函数所访问并赋值,但可以被常成员函数访问。 8. **内联函数**:内联函数是一种优化...
7. **常数据成员初始化**:常数据成员(i)在类的定义中不能直接初始化,必须在构造函数的初始化列表中进行。 8. **内联函数**:内联函数是在编译时展开的,目的是优化程序性能,避免函数调用的开销。因此,它们不会...
初始化结构体时,可以使用`new`运算符调用构造函数,或者直接赋值给结构体的字段,就像对类实例进行操作一样。 2. 结构体的内存管理: 因为结构体是值类型,所以在变量声明时,会在栈上分配内存,而无需像引用类型...
C++编译器会根据需要自动生成一些函数,如默认构造函数、拷贝构造函数、赋值运算符和析构函数等。了解这些函数的工作原理及其行为对于编写高质量的C++代码至关重要。 #### 六、结语 《Effective C++》第三版不仅为...
- 主要类:Assembly用于加载程序集,Module了解模块信息,ConstructorInfo用于构造函数操作。 以上知识点涵盖了.NET Web开发中的页面间通信、C#基础、面向对象特性、数据库操作和JavaScript基础知识,是.NET程序员...
列表初始化是一种更加安全的初始化方式,可以用于构造函数、函数返回值和变量初始化。 **4. 多态** 多态性允许一个接口被不同类的对象所使用。实现多态的方式包括虚函数和抽象类。 **5. 静态绑定与动态绑定** - ...