编译器琐事:这段代码的结果是什么

Joh*_*aft 4 c# compiler-construction behavior

我今天正在审查一些代码并遇到了一些代码(由此代码段准确描述)......

public abstract class FlargBase{
    public FlargBase(){
        this.DoSomething();
    }

    public abstract void DoSomething();
}

public class PurpleFlarg: FlargBase{
    public PurpleFlarg()
      : base(){
    }

    public override void DoSomething(){
        // Do something here;
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器不提供任何错误或警告,但CodeAnalysis警告调用链包含对虚方法的调用,并可能产生意外结果.

我很好奇,因为正如我所看到的,有两件事情可能发生.

  1. 创建基类的实例将调用没有定义实现的方法.我希望编译器出错,或者由于缺少实现而导致运行时抛出异常.我假设编译器提供了{}的实现 我错误输入了原始代码; 它确实在类中包含了abstract关键字.
  2. 创建派生类的实例将导致对尚未实际构造的类的方法的调用.我原以为这会引发异常.

此代码已在生产环境中使用了几个月.它显然工作正常,没有人注意到任何奇怪的行为.

我希望StackOverflow上的不可思议的人才可以让我对这段代码的行为和后果有所了解.

Cod*_*aos 12

在第一个构造函数运行之前,AC#对象已完全构造并初始化为零.基础构造函数将调用虚方法的派生实现.

这样做被认为是不好的样式,因为派生类的构造函数尚未被调用时,派生的实现可能会表现得很奇怪.但这种行为本身就是明确的.如果在派生实现中不执行任何操作,需要构造函数中的代码已经运行,那么它将起作用.

您可以映像运行时首先调用最派生的构造函数.它的第一个动作是隐式调用基础构造函数.我不确定它是否实际上是这样实现的,但是由于某些.net语言允许您在派生构造函数的任意点调用基本构造函数,我希望C#只需调用基类构造函数作为派生的第一个动作构造函数.


此行为与C++处理它的方式非常不同.在C++中,派生类一个接一个地构造,并且在派生类的构造函数启动之前,对象仍然具有基类的类型,并且忽略派生类的覆盖.