为什么C#设置基本构造函数之前私有变量,而VB.NET则正好相反?变量、函数、基本、NET

2023-09-03 10:08:15 作者:誓言是一时的失言

有比较C#code和VB.NET之间的看似相同的code的结果是完全不同的问题。 (为什么C#总是争取VB.NET ?)

There was a question comparing C# code and VB.NET and the results between the seemingly identical code were entirely different. (Why C# is always winning over VB.NET?)

给出的解释是,C#将初始化类字段,然后调用基类的构造,但VB.NET做的正好相反。

The explanation given is that C# will initialize the class fields, then call the base constructor, but VB.NET does the exact opposite.

我的问题是 - 为什么?

My question is - why?

是否有技术原因语言是不同的?乍一看,似乎这两种方法都同样有效,但我无法捉摸,为什么他们就不会选择同样的做法。

Is there a technical reason for the languages to be different? At first glance, it seems that either approach is equally valid, but I can't fathom why they wouldn't have selected the SAME approach.

编辑:作为杰弗里大号Whitledge所指出的那样,VB6没有继承,所以我不认为我们可以说'保持VB.NET和VB6更加密切的关系

As 'Jeffrey L Whitledge' has pointed out, VB6 did not have inheritance, so I don't think we can say 'to keep VB.NET and VB6 more closely related'.

推荐答案

这是可能的基础构造暴露一个对象之前外界派生类的构造函数已经运行。虽然人们经常要避免这样做,有次当它是必要的。例如,一个可能具有其中容纳引用彼此两个对象,每个对象可能具有作为一个类不变,提及的其他对象必须有效。创建这样一对对象需要有一个对象的构造部分构造的对象传递给对方,或有对象的构造函数返回之前它的类不变量是满意的。

It is possible for a base constructor to expose an object to the outside world before derived-class constructors have run. While one should often avoid doing this, there are times when it's necessary. For example, one might have two objects which hold references to each other, and each object might have as a class invariant that the reference to the other object must be valid. Creating such a pair of objects would require having one object's constructor pass the partially-constructed object to the other, or having an object's constructor return before its class invariants were satisfied.

如果派生类的字段初始不会运行,直到基类构造函数运行后,如果基类的构造函数公开对象外面的世界,这将意味着该对象会前,会接触到外面的世界任何派生类的初始化发生了。 C#的创造者并没有这样的想法,所以他们提出了基类的构造函数之前运行派生类初始化。

If derived-class field initializers are not run until after the base class constructor has run, and if the base-class constructor exposes the object to the outside world, that would mean that the object would be exposed to the outside world before any derived-class initialization had taken place. The creators of C# didn't like that idea, so they made derived-class initializers run before the base class constructor.

在另一方面,基类的构造函数之前运行的派生类的初始化有一个缺点:那些初始化不能进行任何引用在建的对象。但也没有办法让他们利用被传递给构造的任何参数。有一个物体被部分初始化的控制交给了前向基类的构造函数可能是好的,但也有一些严格的限制,以如何对其进行初始化;它可以是或不是有可能在一个完全有用状态的对象基构造运行之前。

On the other hand, running derived-class initializers before the base-class constructor has a disadvantage: those initializers can't make any reference to the object under construction. There's also no way for them to make use of any arguments that are passed to the constructor. Having an object be partially initialized before control is handed over to the base-class constructor may be nice, but there are some severe limits as to how it can be initialized; it may or may not be possible to have the object in a fully-useful state before the base constructor is run.

vb.net的创造者显然认为,由于基础构造函数之前运行初始化不排除需要处理部分构造的对象暴露于外部世界,并且由于它precludes使用一些有用的技术,这是最好有基构造后运行初始化。这可以使一个基层构造,露出它的参数作为一个字段中的一个,再有衍生类使用该字段的值在派生类字段初始化。

The creators of vb.net apparently thought that since running initializers before the base constructor doesn't eliminate the need to deal with partially-constructed objects being exposed to the outside world, and since it precludes the use of some useful techniques, it was better to have the initializers run after the base constructor. This makes it possible for a base-level constructor to expose one of its parameters as a field, and then have the derived-class use the value of that field in the derived-class field initializers.

可以说,C#方法允许一做的事情之一是不是就vb.net,但反之则不然(人们可以通过简单地写在田构造开始实施VB风格的场初始值) 。而另一方面,有彼此相邻字段的声明和初始化比在一个地方声明和初始化别的地方清洁。太糟糕了,没有语言允许指定某些特定领域的声明应遵循的规范相反的模式。

Arguably, the C# approach allows one to do things the vb.net one does not, but the reverse isn't true (one could implement vb-style field initializers by simply writing to the fields at the start of the constructor). On the other hand, having the declaration and initialization of a field next to each other is cleaner than having declarations in one place and initializations someplace else. Too bad neither language allows one to specify that certain specific field declarations should follow the opposite paradigm from the norm.