为什么会产生编译错误:
class Foo
{
public Bar Baz = new Bar(this);
}
但这不是:
class Foo
{
public Bar Baz;
public Foo()
{
this.Baz = new Bar(this);
}
}
从概念上讲,两者是等价的,不是吗?
答案 0 :(得分:10)
不,它们不完全相同......变量初始化程序在运行任何基类构造函数之前执行。运行基类构造函数后,构造函数的主体执行。 (这与Java不同,其中变量初始值设定项在基类构造函数之后但在构造函数体之前执行。)
因此,在构造函数体内访问this
会更安全:您可以确保该对象至少在其基类(及以上)方面进行初始化。
我相信这就是推理,无论如何...
答案 1 :(得分:1)
访问尚未初始化的类是不合逻辑的。 如果你能够访问它,那就意味着Bar已经初始化,直到构造函数没有完成才真实。
答案 2 :(得分:1)
因为在那一点(在你的第一个例子中)尚未构建对象。在构造函数中它已经是。
在构造函数体中,您可以选择进行额外的初始化,但只有在您希望的情况下 - 更改字段值,调用其他方法,等等。但这是可选的。因此,您可能会依赖于技术构造的对象,而它可能不是根据您的应用程序逻辑构建的。但是你需要注意的是,而不是编译器。
答案 3 :(得分:1)
因为您引用的类尚未初始化。
答案 4 :(得分:1)
class Foo
{
public Bar Baz = new Bar(this);
}
“this”代表“Foo”类的对象。此时您还没有启动类对象。
假设,“Bar”构造函数不需要“Foo”实例来启动(或调用其构造函数),如Bar(“hello!”),那么上面的语句可以编译为:
class Foo
{
public static Bar Baz = new Bar("Hello!");
}
可以通过以下方式访问:
Foo.Baz.something();
一个类可以启动一个应该用“static”关键字标记的实例,并且不需要启动类实例。
答案 5 :(得分:0)
其他一点没有提到的答案是C#和vb.net中的字段初始化规则不同。在C#中,如果Foo:Bar:Boz:Object,构造函数和字段初始值设定项按顺序运行:
在vb.net中,序列为:
vb.net方法的一个优点是字段初始化程序可以使用正在构造的对象,因为对象及其基类型中的所有内容都已初始化到初始化点。在某些情况下,C#方法可能会有所帮助,但考虑到所谓的优势只适用于虚拟方法所需的字段可以直接初始化的情况下,我认为它们相对较少。或间接需要任何构造函数的参数;这些情况几乎总是可以通过让虚方法检查对象是否已初始化来处理,如果没有则初始化它(它将具有“早期”字段初始化器可用的所有信息)。
坦率地说,如果有一个合理的方法让字段初始化程序访问构造函数参数,我认为vb.net和c#都会得到改进。在vb中,由于字段初始化程序在构造基类之后运行,因此可以使用基类构造函数将其参数存储到字段中,并使派生类构造函数使用该字段初始化其他字段。例如,如果MyArray[]
在对象的整个生命周期中始终引用相同的数组,则说:
' ConstructorParam is defined and set in base class ParamInitClass(Of Integer) ReadOnly MyArray(ConstructorParam) As Integer ... Sub New(ArraySize As Integer) MyBase.New(ArraySize) End Sub
似乎比
更清晰ReadOnly MyArray() As Integer Sub New(ArraySize As Integer) Redim MyArray(ArraySize) End Sub
请注意,在C#中,尝试执行此类操作的唯一方法是通过threadstatic
变量,但这些技术充其量只是狡猾。