基类构造函数被命中而不调用它

本文关键字:调用 构造函数 基类 | 更新日期: 2023-09-27 18:31:49

给定代码:

public class A
{
    public A()
    {
        throw new Exception();
    }
}
public class B : A
{
    public B(int i)
    {
    }
}

然后运行该行:

  var x = new B(2);

我永远不会期望A的构造函数被击中(除非我添加base())到B的构造函数声明的末尾。

奇怪的是,它似乎被击中了(并抛出了异常)。这是默认行为吗?这让我很惊讶,因为我完全没想到A的构造函数会被击中

基类构造函数被命中而不调用它

如果您不包含任何base(..)this(..),它的作用与base()相同。从 C# 规范:


如果实例构造函数没有构造函数初始值设定项

,则会隐式提供形式 base() 的构造函数初始值设定项。因此,窗体的实例构造函数声明

C(...) {...}

完全等同于

C(...): base() {...}

您可能一直在寻求使A成为abstract class,以便无法直接创建A的实例。

public abstract class A
{
}
public class B : A
{
    public B(int i)
    {
    }
}
public static void Main()
{
    // A a = new A(); // doesn't compile
    A a = new B(2); // valid
}

但是在 class.so A 继承的 B 类中,当您在 B 实例上创建时,也会自动启动 A 实例。这是 OOP 概念中的默认行为。

这是

默认行为。构造函数按从基类第一个到继承类最后一个的顺序运行。当你编写base()时,你可以将一些值直接传递给base构造函数

例如

public class B : A
{
    public B(int i): base(i)
    {
    }
}

正如您的评论者所提到的,这是默认的 C# 行为。 必须调用每个基类上的构造函数。

如果您的规则是永远不应构造类 A(仅子类),请将类 A 声明为抽象

public abstract class A {}

使用该语法,如果您尝试构造 A(但 B 可以),这将是一个编译时错误,因此您可以删除 A 构造函数中的抛出。

这是意料之中的:如果未显式指定构造函数的不同重载,则默认情况下将始终调用它。即使您确实指定了要调用的不同重载,它也将传播到其基类的构造函数,直到它到达根Object()构造函数。

请注意,这也意味着,如果在单个类中具有不同的构造函数重载,则通过重载构造函数实例化对象将不会调用同一类的无参数构造函数,而是调用基类的无参数构造函数(在本例中为 Object()):

public class A
{
    public A()
    {
        throw new Exception();
    }
    public A(int i)
    {
        // this will not call the A(), but the base Object() constructor
    }
}
var a = new A(5); // no exception thrown