关于构造函数及参数执行顺序说明(c#)

以前自己对这方面的内容一直比较模糊,只是知道一个大概的顺序,具体确切的执行顺序不能确定,于是抽空做了一个详细的测试,对其进行一番研究.
具体的程序代码比较简单,如下所示.
三个类分开来写的,一个父类,一个子类,一个测试类:

父类:

using System;

namespace TestInherit
{
 public class Father
 {
  public int father_a=111;
  public int father_aa=1111;
  public readonly int father_c=7777;
  public static int father_e=222;
  public static int father_ee;
  static Father()
  {
   father_e=5555;
   father_ee=3333;
  }

  public Father()
  {
   father_ee=4444;
  }
  public Father(int a)
  {
   father_a=a;
  }    
 }
}

子类:

using System;

namespace TestInherit
{
 public class Son:Father
 {  
  public int son_int=9999;
  public static int son_b=111;
  public static int son_c;
  public Son()
  {
   son_c=222;   
  }
  static Son()
  {
   son_c=333;
  }
  public Son(int a)
  {
   son_int=a;
  }
 }
}

测试类:

using System;

namespace TestInherit
{
 class Class1
 {
  [STAThread]
  static void Main(string[] args)
  {
    Son son1=new Son ();
  }
 }
}

然后一路F11,进行跟踪,可以得到完整的执行顺序如下所示:

  1. 子类静态变量;
  2. 子类静态构造函数;
  3. 子类非静态变量;
  4. 父类静态变量;
  5. 父类静态构造函数;
  6. 父类非静态变量;
  7. 父类无参构造函数;
  8. 子类无参构造函数;

提供的代码中,执行顺序是根据C#语言规范的定义来进行的,而不是所谓的“优先”来执行的。让我们来具体分析一下执行过程:

  1. 子类静态变量和静态构造函数:

    • son_bson_c 是子类 Son 的静态变量,在类第一次被使用时进行初始化。son_c 的初始化是在静态构造函数中完成的。
    • 执行 static Son(),因此 son_c 被设置为 333。
  2. 子类非静态变量:

    • son_int 是子类 Son 的非静态变量,会在实例化对象时进行初始化。
    • 实例化 Son 对象时,执行 Son son1 = new Son();son_int 被设置为9999。
  3. 父类静态变量和静态构造函数:

    • father_efather_ee 是父类 Father 的静态变量,在类第一次被使用时进行初始化。father_ee 的初始化是在静态构造函数中完成的。
    • 执行 static Father(),因此 father_e 被设置为 5555,father_ee 被设置为 3333。
  4. 父类非静态变量:

    • father_a, father_aa, 和 father_c 是父类 Father 的非静态变量,会在实例化对象时进行初始化。
    • 执行 Father() 构造函数,因此 father_a 被设置为111,father_aa 被设置为1111,father_c 被设置为 7777。
  5. 父类无参构造函数:

    • 执行 Father() 构造函数体,因此 father_ee 被覆写设置为 4444。
  6. 子类无参构造函数:

    • 执行 Son() 构造函数体,son_c被覆写成222。

在这里插入图片描述

所以,子类非静态变量并没有“优先”于父类无参构造函数,而是在实例化子类对象时按照语言规范的定义进行的初始化顺序。

如果Main()方法中改为Son son1=new Son (111),顺序为;

  1. 子类静态变量;
  2. 子类静态构造函数;
  3. 子类非静态变量;
  4. 父类静态变量;
  5. 父类静态构造函数;
  6. 父类非静态变量;
  7. 父类无参构造函数;
  8. 子类有参构造函数;

如果子类的有参构造函数改为:

 public Son(int a):base(a)
 {
  son_int=a;
 }

则顺序又有所改变:

  1. 子类静态变量;
  2. 子类静态构造函数;
  3. 子类非静态变量;
  4. 父类静态变量;
  5. 父类静态构造函数;
  6. 父类非静态变量;
  7. 父类有参构造函数;
  8. 子类有参构造函数;

以上测试改为父类声明,子类实现,结果也是一样,即main()方法中改为Father son1=new Son ();

最后作一个总结:
1.一般原理是被依赖的先构造,依赖于人的后构造(PS:在面向对象的继承关系中,父类的构造函数会在子类的构造函数之前执行,确保被依赖的先构造。),c#中是同层依赖(成员变量,其他的类变量等)优先于跨层依赖(父子关系)构造(注意java中正好相反);(子类的变量是不是可以理解为同层的依赖呢??)

2.静态构造函数,静态参数都是优先于非静态构造函数,非静态参数构造或初始化;


C#构造函数的执行顺序

构造函数的作用是初始化一个新对象,构造函数实在对象初始化的时候优先调用。readonly 字段可以直接在定义中进行赋值,也可在构造函数中对其进行赋值,其他地方不能对其进行赋值。

构造函数的执行顺序:如下

public class MyBaseClass
    {
        public MyBaseClass()
        {

        }

        public MyBaseClass(int i)
            : this()
        {

        }

        public MyBaseClass(int i, int j)
        {

        }
    }


public class MyDrivedClass : MyBaseClass
    {
        public MyDrivedClass()
            : base(0)
        {

        }

        public MyDrivedClass(int i)
        {

        }

        public MyDrivedClass(int i, int j)
            : base(i)
        {

        }
    }

class Program
    {
        static void Main(string[] args)
        {
            //执行顺序System.Object()->MyBaseClass()->MyBaseClass(int i)->MyDrivedClass()
            //MyDrivedClass md = new MyDrivedClass();

            //执行顺序System.Object()->MyBaseClass()->MyDrivedClass(int i)
            //int i = 0;
            //MyDrivedClass md = new MyDrivedClass(i);

            //若要不执行默认构造函数,需要添加继承base(canshu)或this(canshu)

            //执行顺序System.Object()->MyBaseClass()->MyBaseClass(int i)->MyDrivedClass(int i, int j)
            MyDrivedClass mdc = new MyDrivedClass(7, 8);
        }
    }

base关键字是指向的基类构造方法,this关键字是指向本类的构造方法。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值