构造函数

79 阅读2分钟

使用静态构造函数

静态构造函数会在类的任何实例被创建之前或者任何静态成员被引用之前自动执行,所以可以在静态构造函数里进行判断。

子类实例化时会自动触发父类的构造函数,但具体执行规则需要根据父类构造函数的类型(无参构造函数或有参构造函数)和子类的实现方式来区分。

1. 自动调用父类的无参构造函数

如果父类定义了无参构造函数(或没有显式定义任何构造函数,编译器会自动生成一个默认无参构造函数),子类实例化时会自动调用该无参构造函数,无需显式指定。

示例代码

csharp

public class Parent
{
    public Parent()
    {
        Console.WriteLine("父类无参构造函数被调用");
    }
}

public class Child : Parent
{
    public Child()
    {
        Console.WriteLine("子类构造函数被调用");
    }
}

// 实例化子类
var child = new Child();

// 输出结果:
// 父类无参构造函数被调用
// 子类构造函数被调用

执行顺序

  1. 父类构造函数先执行,完成父类的初始化。
  2. 再执行子类构造函数,完成子类的初始化。

2. 手动调用父类的有参构造函数

如果父类只有有参构造函数(没有无参构造函数),子类必须显式调用父类的某个有参构造函数,否则会编译错误。

示例代码

csharp

public class Parent
{
    public Parent(string message)
    {
        Console.WriteLine($"父类有参构造函数被调用:{message}");
    }
}

public class Child : Parent
{
    // 使用 base 关键字显式调用父类有参构造函数
    public Child() : base("来自子类的消息")
    {
        Console.WriteLine("子类构造函数被调用");
    }
}

// 实例化子类
var child = new Child();

// 输出结果:
// 父类有参构造函数被调用:来自子类的消息
// 子类构造函数被调用

关键点

  • 使用 base(参数) 语法在子类构造函数中显式调用父类构造函数。
  • 若父类没有无参构造函数,子类必须通过 base 指定调用哪个有参构造函数。

3. 静态构造函数的执行规则

静态构造函数(static 修饰)只会执行一次,且在任何实例构造函数之前执行。父类和子类的静态构造函数执行顺序如下:

示例代码

csharp

public class Parent
{
    static Parent()
    {
        Console.WriteLine("父类静态构造函数被调用");
    }

    public Parent()
    {
        Console.WriteLine("父类实例构造函数被调用");
    }
}

public class Child : Parent
{
    static Child()
    {
        Console.WriteLine("子类静态构造函数被调用");
    }

    public Child()
    {
        Console.WriteLine("子类实例构造函数被调用");
    }
}

// 实例化子类
var child = new Child();

// 输出结果:
// 父类静态构造函数被调用
// 子类静态构造函数被调用
// 父类实例构造函数被调用
// 子类实例构造函数被调用

执行顺序

  1. 父类静态构造函数(第一次使用该类时执行)。
  2. 子类静态构造函数(第一次使用该类时执行)。
  3. 父类实例构造函数(每次实例化时执行)。
  4. 子类实例构造函数(每次实例化时执行)。

4. 构造函数链的执行规则

如果子类构造函数有多个重载,且通过 this() 调用其他构造函数,父类构造函数只会执行一次,且在所有子类构造函数逻辑之前执行。

示例代码

csharp

public class Parent
{
    public Parent()
    {
        Console.WriteLine("父类构造函数被调用");
    }
}

public class Child : Parent
{
    public Child() : this("默认消息")
    {
        Console.WriteLine("子类无参构造函数被调用");
    }

    public Child(string message)
    {
        Console.WriteLine($"子类有参构造函数被调用:{message}");
    }
}

// 实例化子类
var child = new Child();

// 输出结果:
// 父类构造函数被调用
// 子类有参构造函数被调用:默认消息
// 子类无参构造函数被调用

执行顺序

  1. 父类构造函数。
  2. 子类有参构造函数(被 this() 调用)。
  3. 子类无参构造函数(实际执行的构造函数)。

总结

场景父类构造函数执行规则
父类有无参构造函数子类自动调用,无需显式指定
父类只有有参构造函数子类必须通过 base(参数)显式调用
静态构造函数父类和子类的静态构造函数各自执行一次,在实例构造函数之前
构造函数链( this()父类构造函数只执行一次,在子类构造函数链的最前端

核心原则:父类的初始化逻辑(构造函数)总是在子类之前执行,确保对象的继承层次正确初始化。