在调用基类型构造函数之前,是否可以强制 VB.NET 初始化实例变量?

问题描述:

在 VB.NET 中调试了一个涉及实例变量初始化顺序的特别棘手的问题后,我发现我对 C# 的预期行为与 VB.NET 中的实际行为之间存在重大差异.

After debugging a particularly tricky issue in VB.NET involving the order in which instance variables are initialized, I discovered that there is a breaking discrepancy between the behavior that I expected from C# and the actual behavior in VB.NET.

注意事项:这个问题涉及 VB.NET 和 C# 的行为略有差异.如果您是一个语言偏执狂,除了这就是为什么您应该使用 C#,菜鸟"之外无法提供答案,那么这里没有什么可看的;请继续前进.

Nota bene: This question concerns a slight discrepancy in the behaviors of VB.NET and C#. If you're a language bigot that is unable to provide an answer other than "that's why you should use C#, noob", there is nothing for you to see here; kindly move along.

具体来说,我期望 C# 语言规范中概述的行为>(强调):

Specifically, I expected the behavior outlined by the C# Language Specification (emphasis added):

当一个实例构造器没有构造器初始化器,或者它有一个 base(...) 形式的构造器初始化器时,该构造器隐式地执行由实例的变量初始化器指定的初始化在其类中声明的字段.这对应于在进入构造函数和隐式调用直接基类构造函数之前立即执行的赋值序列.变量初始值设定项按照它们出现在构造函数中的文本顺序执行类声明.

When an instance constructor has no constructor initializer, or it has a constructor initializer of the form base(...), that constructor implicitly performs the initializations specified by the variable-initializers of the instance fields declared in its class. This corresponds to a sequence of assignments that are executed immediately upon entry to the constructor and before the implicit invocation of the direct base class constructor. The variable initializers are executed in the textual order in which they appear in the class declaration.

与 VB.NET 语言规范中关于实例构造函数,表示(强调):

Contrast that with the portion of the VB.NET Language Specification concerning Instance Constructors, which says (emphasis added):

当构造函数的第一条语句采用 MyBase.New(...) 形式时,构造函数隐式地执行由类型中声明的实例变量的变量初始值设定项指定的初始化.这对应于在调用直接基类型构造函数后立即执行的赋值序列.这种排序确保所有基实例变量在访问实例的任何语句之前由它们的变量初始化器初始化执行.

When a constructor's first statement is of the form MyBase.New(...), the constructor implicitly performs the initializations specified by the variable initializers of the instance variables declared in the type. This corresponds to a sequence of assignments that are executed immediately after invoking the direct base type constructor. Such ordering ensures that all base instance variables are initialized by their variable initializers before any statements that have access to the instance are executed.

这里的差异很明显. C# 在调用基本构造函数之前 初始化类级变量.VB.NET 正好相反,显然更喜欢在设置实例字段的值之前调用基本构造函数.

The discrepancy here is immediately obvious. C# initializes class-level variables before calling the base constructor. VB.NET does exactly the reverse, apparently preferring to call the base constructor before setting the values of instance fields.

如果你想看一些代码,这个相关问题 提供了一个更具体的发散行为示例.不幸的是,它没有提供关于如何强制 VB.NET 遵循 C# 建立的模型的任何提示.

If you want to see some code, this related question provides a more concrete example of the divergent behavior. Unfortunately, it does not provide any hints as to how one might coerce VB.NET into following the model established by C#.

我对为什么这两种语言的设计者选择如此不同的方法感兴趣,而不是对问题的可能解决方法感兴趣.最终,我的问题如下:有什么方法可以在 VB.NET 中编写或构建我的代码以强制在调用基类型的构造函数之前初始化实例变量strong>,这是 C# 中的标准行为吗?

I'm less interested in why the designers of the two languages chose such divergent approaches than I am in possible workarounds for the problem. Ultimately, my question is as follows: Is there any way that I can write or structure my code in VB.NET to force instance variables to be initialized before the base type's constructor is called, as is the standard behavior in C#?

如果您有将在构建期间调用的虚拟成员(违背最佳建议,但我们已经同意),那么您需要移动您的初始化到一个单独的方法中,可以保护自己免受多次调用(即如果 init 已经发生,则立即返回).然后,该方法将由虚拟成员和您的构造函数调用,然后才依赖于已发生的初始化.

If you have virtual members that are going to be invoked during construction (against best advice, but we've already agreed on that), then you need to move your initialization into a separate method, that can protect itself against multiple calls (i.e. if init has already happened, return immediately). That method will then be invoked by the virtual members and your constructor, before they rely on initialization having occurred.

它有点乱,可能会造成轻微的性能损失,但在 VB 中您几乎无能为力.

It's a bit messy, and may represent a minor performance penalty, but there's little else you can do in VB.