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

原文地址:https://www.cnblogs.com/aaa6818162/p/4798213.html