• 6 CLR实例构造器


    引用类型构造器

    如果我们没有定义实例构造器,那么编译器会为我们默认产生一个无参构造器。

    实例对象初始化过程

    • 为实例分配内存;
    • 初始化附加成员,包括方法表指针和SyncBlockIndex变量(我们已经在

      image

      image

      调用顺序

      如果类没有显示定义构造器,编译器会自动生成一个无参构造器,调用基类的无参构造器。例如

      public class Animal{}

      相当于

      public class Animal

      {

         public Animal():base(){}

      }

      如果类的修饰符为static(sealed和abstract),编译器不会默认生成构造器;

      如果基类没有提供无参构造器,那么派生类必须显示调用一个构造器,否则编译错误。

      如果存在继承关系,派生类在使用基类的字段之前应该先调用基类的构造器。如果派生类没有显式调用基类构造器,则编译器会自动产生调用基类无参构造器的代码,沿着继承层次一直到System.Object的无参构造器位置。例如下面,调用Dog dog=new Dog()方法的结果。

      image

      class Dog:Animal。。。

      image

      Dog()方法IL代码

      image

      代码爆炸?

      为了防止构造器重载时大量重复赋值造成代码膨胀,我们建议将公共的初始化语句放在一个构造函数中,然后其他的构造器显式调用该构造器。

     class A
            {
                public int xxxx = 100;
                public int xxxx2 = 100;
                public int xxxx3 = 100;
    
                public A()
                {
                    Console.WriteLine("我是类A的无参构造器");
                }
    
                public A(string ss)
                {
                    Console.WriteLine("我是类A的无参构造器");
                }
            }
    
            //编译后等价于
            class A
            {
                public int xxxx;
                public int xxxx2;
                public int xxxx3;
    
                public A()
                {
                    xxxx = 100;
                    xxxx2 = 100;
                    xxxx3 = 100;
                    Console.WriteLine("我是类A的无参构造器");
                }
    
                public A(string ss)
                {
                    xxxx = 100;
                    xxxx2 = 100;
                    xxxx3 = 100;
                    Console.WriteLine("我是类A的无参构造器");
                }
            }
    
    
            /// <summary>
            /// ////////////////////////////////////////////////////////////////////////////////////////////////
            /// </summary>
            class A
            {
                public int xxxx = 100;
                public int xxxx2 = 100;
                public int xxxx3 = 100;
    
                public A()
                {
                    Console.WriteLine("我是类A的无参构造器");
                }
    
                //防止代码爆炸
                public A(string ss):this()
                {
                    Console.WriteLine("我是类A的无参构造器");
                }
            }
    
            //编译后等价于
            class A
            {
                public int xxxx;
                public int xxxx2;
                public int xxxx3;
    
                public A()
                {
                    xxxx = 100;
                    xxxx2 = 100;
                    xxxx3 = 100;
                    Console.WriteLine("我是类A的无参构造器");
                }
    
                public A(string ss):this()
                {
                    Console.WriteLine("我是类A的无参构造器");
                }
            }

    值类型构造器

    • 值类型没有默认产生的无参构造器,也不允许我们定义无参构造器。但是我们可以自定义带参数的构造器。

    image

    • 不允许在值类型中内联实例字段的初始化。下面的例子会产生编译错误。
      struct TestStruct
          { 
             partial int number=5;
          }
    • 值类型带参构造函数必须对所有实例字段进行初始化才可以。如果有变量没有初始化,就会报错。

    image 

    如果不想对所有字段一一初始化,有一种替代方案:

    复制代码
      struct Dog
        {
            public int age;
            public string name;
            public Dog(string Name)
            {
                this = new Dog();
                name = Name;
            }
        }
    复制代码

    在值类型构造器中,this代表值类型本身的一个实例,用New创建的值类型实例赋给this时,会将所有字段置零。所以这个方案可以编译通过。

    • 带参构造函数定义之后需要用new显式调用才能执行。否则值类型的字段会保持0或Null值。

    image     image

  • 相关阅读:
    java web 工程更改名字
    [转]Eclipse下开发Struts奇怪异常:org.apache.struts.taglib.bean.CookieTei
    【转】myeclipse 自定义视图Customize Perspective 没有反应
    latex建立参考文献的超链接
    latex 脚注编号也成为超链接
    自定义标签TLD文件中,rtexprvalue子标签的意思
    设计模式观察者
    设计模式模板方法
    设计模式策略
    设计模式享元
  • 原文地址:https://www.cnblogs.com/aaa6818162/p/4798213.html
Copyright © 2020-2023  润新知