C# 为什么子类变量在父类成员变量之前初始化

C# 为什么子类变量在父类成员变量之前初始化,c#,inheritance,constructor,initialization,C#,Inheritance,Constructor,Initialization,考虑下面的代码。字段i和j在m和n之前初始化。我们知道父对象是在子对象之前创建的,但在我的程序中,编译器正在为子类“基类之前的成员变量”分配和初始化内存。为什么呢 class X { private int m = 0; private int n = 90; public X() { } } class Y:X { private int i = 8; private int j = 6; public Y() { } publ

考虑下面的代码。字段
i
j
m
n
之前初始化。我们知道父对象是在子对象之前创建的,但在我的程序中,编译器正在为子类“基类之前的成员变量”分配和初始化内存。为什么呢

class X
{
    private int m = 0;
    private int n = 90;
    public X() { }
}

class Y:X
{
    private int i = 8;
    private int j = 6;
    public Y()
    { }
    public static void Main(string []args)
    {
        Y y1 = new Y();  
    }
}

必须允许子结构代码调用父结构上的函数,除非父结构已经完全构造,否则父结构无法工作

但是,这些对象共享同一个内存块。因此,所有内存一次分配完毕,然后根据类层次结构初始化类。

这在以下章节中进行了说明:

[…]一个初始化的只读字段总是在其初始化状态下被观察到,除非我们先运行所有的初始化器,然后运行所有的构造函数体,否则我们无法保证这一点

不确定为什么这里提到了
readonly
,但例如,这确保了以下场景(尽管很愚蠢)能够正常工作:

一,

二,

(17.10.2)中明确规定了该顺序:

[…]构造函数隐式执行其类中声明的实例字段的变量初始值设定项指定的初始化。这对应于一系列赋值,这些赋值在进入构造函数之后和隐式调用直接基类构造函数之前立即执行


这是对过程方法学的理解使面向对象方法学更容易理解的少数地方之一。即使您使用的是OOP,编译器仍然遵循过程逻辑——从开始到结束

一个简单的例子是编译器点击
private int n=90
。首先,它为一个整数值分配空间,然后是一个标识符,将其作为一个整数访问,然后为其分配值90。它不能赋值,除非它有空间粘贴它并知道如何访问它,也不能访问不存在的空间


在本例中,派生类
Y
构建在基类
X
之上,类似于上例中变量
n
构建在“类”
整数
之上的方式。这是由声明
类Y:X
触发的-编译器甚至无法开始构建
Y
,直到它理解如何构建
X

才清楚您的问题是什么。i和j在m和n之前初始化,我们知道父对象比子对象先创建,但在我的程序编译器中,为基类之前的子类成员变量分配和初始化内存时,“我们知道父对象是在子对象之前创建的”并不是必需的true语句<代码>Y是一个具有4个字段的单个对象-因此将同时为所有4个字段分配空间。在BartoszKP的+1答案中的链接中介绍了初始化的顺序。但OP说子字段是在父字段之前初始化的fields@Juli我们在描述不同的关系。类之间以及对象之间都存在父/子关系。我不明白你的意思。您的意思是必须完全构造父级,子级才能调用其函数,这意味着应该首先初始化父级,对吗?OP是说首先初始化的是孩子。
class Base
{
    public Base()
    {
        if (this is Derived) (this as Derived).Go();
    }
}

class Derived : Base
{
    X x = new X();

    public void Go()
    {
        x.DoSomething(); // !
    }
}
class Base
{
    public Base()
    {
        Go();
    }

    public virtual Go() {}
}

class Derived : Base
{
    X x = new X();

    public override void Go()
    {
        x.DoSomething(); // !
    }
}