`

c# 变量的 内联赋值 vs. 构造函数内赋值

    博客分类:
  • c#
c# 
阅读更多

上下文: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

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    C++单项选择复习题

    赋值兼容规则和构造函数: 1. 赋值兼容规则只在公有继承下成立,基类对象可以赋值给派生类对象,但反之则不行。 2. 派生类构造函数需要初始化直接和间接基类,以及子对象。 3. 多重继承可能会导致二义性,解决...

    C#中的结构体详解笔记

    然而,与类有所不同的是,结构体必须至少有一个无参数构造函数。这是因为值类型的默认初始化要求所有的字段都必须有一个初始值。 ```csharp public struct AddressBook { public string Name; public string ...

    一道关于实例化顺序的C#面试题

    通过分析这道面试题,我们可以了解到C#实例化顺序的规则:首先调用静态构造函数,然后调用实例构造函数。同时,我们也需要了解内联方式初始化字段、类型构造器的执行时间和基类和子类实例化的顺序。只有通过深入的...

    C#基础概念.doc

    //运行时会抛出错误,因为 readonly 变量一旦初始化就不允许再次赋值 //Console.WriteLine("strReadOnly: {0}", Class1.strReadOnly); Console.ReadLine(); } }} 结果: strConst: Const 运行时会抛出错误:System....

    C++基础知识全面汇总

    44. **构造函数与析构函数**:构造函数用于初始化对象,而析构函数用于清理资源。 45. **成员函数与友元函数**:成员函数是类的一部分,而友元函数不是类的一部分,但可以访问类的私有成员。 46. **静态成员与实例...

    Effective C++中文版第三版 高清PDF带目录

    - 构造函数的初始化列表:推荐使用初始化列表来初始化成员变量,而不是在构造函数体中赋值。 - 析构函数的虚函数性:确保基类的析构函数为虚函数,以支持多态删除派生类对象。 2. **内存管理** - 智能指针:利用...

    C#语法全解详细教程

    - **构造函数**:初始化新对象时调用,有默认构造函数和自定义构造函数。 - **属性与字段**:属性用于安全地访问和修改对象的数据,字段是类中的私有数据存储。 3. **继承与多态** - **继承**:一个类可以从另一...

    more Effective C# 改善C#的50个具体办法(中文版)

    7. **使用readonly字段确保数据不可变**:readonly字段在构造函数之外不能被赋值,常用于实现线程安全的不变对象。 8. **理解并应用隐式线程局部变量**:在多线程环境中,隐式线程局部变量保证每个线程都有独立的...

    C#语法全解

    - **构造函数** - 用于初始化新创建的对象。 - **属性** - 提供了一种访问类字段的方式,类似于方法调用。 - **索引器** - 允许类通过索引来访问其成员。 - **事件** - 一种特殊的委托类型,用于通知其他对象...

    C#基础概念二十五问

    常量在编译时被内联,而readonly字段在运行时通过构造函数初始化。 3. extern是什么意思? extern关键字用于引入外部定义的函数或库,通常用于C/C++代码的互操作,例如调用操作系统API。 4. abstract是什么意思?...

    Efficient.C++ Performance Programming Techniques

    理解何时使用移动构造函数和移动赋值运算符,而不是传统的拷贝构造函数和赋值运算符,能够减少不必要的资源复制,提高性能。 3. **STL容器的使用**:标准模板库(STL)提供了多种容器,如向量、列表、集合等。选择...

    Jave script 语法电子手册

    创建对象的方式包括字面量语法和构造函数。`this`关键字指向当前上下文,而`prototype`用于继承。 6. 数组: JavaScript的数组可以用方括号表示,支持方法如`push`、`pop`、`shift`、`unshift`、`slice`等。ES6...

    大学asp课程考试基础题目.doc

    定义类时,构造函数不是必需的,但可以提供默认行为。 24. 基于类的CSS样式前缀为".",基于ID的样式前缀为"#"。 25. CSS样式可以内联、在元素中或外部样式表中定义。 26. JavaScript代码通常包裹在标签内,用于在...

    C++复习题.docx

    7. **常数据成员**:常数据成员(const data member)一旦在构造函数初始化列表中初始化,就不能再被修改。它们不能被一般成员函数所访问并赋值,但可以被常成员函数访问。 8. **内联函数**:内联函数是一种优化...

    C++复习题.pdf

    7. **常数据成员初始化**:常数据成员(i)在类的定义中不能直接初始化,必须在构造函数的初始化列表中进行。 8. **内联函数**:内联函数是在编译时展开的,目的是优化程序性能,避免函数调用的开销。因此,它们不会...

    浅析C# 结构体struct

    初始化结构体时,可以使用`new`运算符调用构造函数,或者直接赋值给结构体的字段,就像对类实例进行操作一样。 2. 结构体的内存管理: 因为结构体是值类型,所以在变量声明时,会在栈上分配内存,而无需像引用类型...

    effective c++ 3rd 英文版

    C++编译器会根据需要自动生成一些函数,如默认构造函数、拷贝构造函数、赋值运算符和析构函数等。了解这些函数的工作原理及其行为对于编写高质量的C++代码至关重要。 #### 六、结语 《Effective C++》第三版不仅为...

    面试题汇总

    - 主要类:Assembly用于加载程序集,Module了解模块信息,ConstructorInfo用于构造函数操作。 以上知识点涵盖了.NET Web开发中的页面间通信、C#基础、面向对象特性、数据库操作和JavaScript基础知识,是.NET程序员...

    觅职渣记-互联网技术类笔试面试总结

    列表初始化是一种更加安全的初始化方式,可以用于构造函数、函数返回值和变量初始化。 **4. 多态** 多态性允许一个接口被不同类的对象所使用。实现多态的方式包括虚函数和抽象类。 **5. 静态绑定与动态绑定** - ...

Global site tag (gtag.js) - Google Analytics