gpt4 book ai didi

c# - 为什么派生类的字段初始化器在基类的初始化器之前执行

转载 作者:太空狗 更新时间:2023-10-29 22:54:29 29 4
gpt4 key购买 nike

构造函数按照从上到下的顺序执行 I.E.基础的第一个然后是派生的。这种安排基于一个重要的 OOP 保证,即一个对象(此处为基)必须始终在使用之前进行初始化(此处为派生类的构造函数)。

我想知道为什么字段初始化器在 C# 中不遵循这个原则?我在这里遗漏了什么吗?

我也发现了这个原则对字段初始化器的有用性。我有一个基类,其属性返回 Identity 对象。每个派生类都有自己的存储库字段,我一直在使用字段初始化器(使用默认构造函数)对其进行初始化。最近我决定还必须为存储库类提供 Identity 对象,因此我在存储库构造函数中引入了一个额外的参数。但我坚持要找出:

public class ForumController : AppControllerBase
{
ForumRepository repository = new ForumRepository(Identity);
// Above won't compile since Identity is in the base class.

// ... Action methods.
}

现在我只剩下一个选择,那就是用默认构造函数填充我的每个 Controller ,以便仅完成使用 Identity 初始化存储库对象的工作。

最佳答案

在 C# 中,构造函数运行序列:

  Perform all field initializers  Chain to base class constructor  Execute user-supplied code for constructor

在vb.net中,顺序是:

  Chain to base class constructor  Perform all field initializers  Execute user-supplied code for constructor

没有基于框架的原因说明为什么 C# 会按照它执行的顺序执行操作,事实证明 vb.net 可以并且确实以不同的顺序执行它们。 C# 方法的设计理由是,在所有字段初始化器(对于派生类和基类字段)运行之前,不应该有对象暴露给外界的可能性;由于基类构造函数可以将对象暴露给外界,强制执行该要求意味着字段初始化程序必须在基类构造函数之前运行。

就我个人而言,我并不认为这种理由特别有说服力。在许多情况下,如果没有在基本构造函数运行之前不可用的信息,就不可能将字段设置为有用的值。任何其基础构造函数可能公开部分构造的实例的代码都需要为这种可能性做好准备。虽然有时指定字段初始值设定项应该“尽早”运行是有用的,但我认为还有更多情况下它们能够访问初出茅庐的对象(在某种程度上是因为我相信在类实例的生命周期中,其值应被视为不变量的类字段应在实际情况下通过初始化程序以声明方式设置,而不是在构造函数中强制设置)。

顺便说一下,我希望在 vb.net 和 C# 中看到的一个功能是声明参数初始化字段和伪字段的方法。如果一个类具有特定名称和类型的参数初始化字段,则该类的每个不链接到同一类的另一个构造函数的构造函数都必须包含具有适当名称和类型的参数。这些字段的值将在其他任何事情完成之前在构造函数中设置,并且可以被其他字段初始化程序访问。伪字段在语法上的行为类似于字段,只是它们在字段初始值设定项中可用,并且在构造函数中作为局部变量实现。这样的功能将使许多类型的结构更加方便。例如,如果一个类型应该在其整个生命周期中保存一个特定的数组实例,那么可以说:

  readonly param int Length;  readonly ThingType[] myArray = new ThingType[Length];

似乎比必须在类构造函数中构造数组(这在基类构造函数运行之后才会发生)或(对于 vb.net)必须将长度传递给基类构造函数更好然后可以使用它来设置一个字段(然后会占用类中的空间,即使它的值——如上面的 Length——可能是多余的)。

关于c# - 为什么派生类的字段初始化器在基类的初始化器之前执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7106439/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com