嵌套 class - 这不是一个不完整的类型吗

Nested class - isn't this an incomplete type

示例代码:

public class SimpleClass
{
    private NestedClass nestedClass = new NestedClass();

    public class NestedClass : SimpleClass          
    {

    }
}

// when instantiating in say.. main()
SimpleClass simpleClass = new SimpleClass();

我有 C++ 背景,所以我很难理解这里发生的事情。具体如何在SimpleClass中实例化NestedClass。由于理想情况下,编译器需要 SimpleClass 的完整布局才能实例化 NestedClass,而这又需要 SimpleClass。它本质上有点递归。

这就是我们 运行 这段代码时发生的情况。我们得到一个 Whosebug :) 异常!

在 C++ 世界中,编译器在这种情况下会叫“incomplete type”。

所以我的问题的关键是:

  1. 这是怎么回事,编译器是怎么布局的class(我知道它的实现细节,但是没有完整的类型我们怎么实例化一个对象?)

  2. 这个运行时间异常是故意的,还是应该是编译时错误?

它是一个嵌套 class 的事实在这里无关紧要。它是 derived class 的事实更为重要。除了关于泛型和访问的细节(例如,嵌套 classes 可以访问包含 class 的私有成员),嵌套 class 和非嵌套 [=57] 之间的区别相对较小=].

所以让我们证明:

class BaseClass
{
    DerivedClass derived = new DerivedClass();
}

class DerivedClass : BaseClass
{
}

这仍然可以编译,如果您尝试创建 BaseClass(或 DerivedClass)的实例,仍然会失败并显示 WhosebugException

布局 很好:BaseClass 有一个字段,它是对 DerivedClass 的引用。就知道 "how big" 或 BaseClassDerivedClass 而言没有问题 - 实际上没有初始化方面,这绝对没问题。这里重要的是DerivedClass是一个引用类型,所以derived字段的值是只是一个引用。

这里没有违反 C# 语言规则,设计一种语言规则来禁止这种情况而不禁止有效用例将非常困难。

这里的递归实际上与您可以用单个 class:

做的事情没有什么不同
class BaseClass
{
    BaseClass other = new BaseClass();
}

同样,它是完全有效的代码,但会导致堆栈溢出。


怀疑你想到的问题很容易用结构证明,尽管不涉及继承:

struct Tweedledum
{
    Tweedledee dee;
}

struct Tweedledee
{
    Tweedledum dum;
}

失败,因为没有合适的布局:Tweedledum 值直接包含 Tweedledee 值,反之亦然。非参考:实际值。

这里的错误是:

error CS0523: Struct member 'Tweedledum.dee' of type 'Tweedledee' causes a cycle in the struct layout
error CS0523: Struct member 'Tweedledee.dum' of type 'Tweedledum' causes a cycle in the struct layout