这两者有什么区别?
class Class1
{
public int a = 1;
}
class Class2
{
public int a;
public Class2()
{
a = 1;
}
}
如果没有,我可以跳过默认构造函数并像Class1
一样初始化我的变量吗?
答案 0 :(得分:8)
调用new Class1()
首先将a
设置为1
,然后调用基类构造函数。
首先调用new Class2()
调用基类构造函数,然后将a
设置为1
。
由于您是从object
派生的,因此基类构造函数不执行任何操作。在其他情况下,它可能会有所不同。
答案 1 :(得分:8)
您不会注意到代码中的差异,但不同之处在于调用和初始化事物的顺序:
因此,在Class1
中,字段在步骤1中初始化。在Class2
中,字段在步骤1中初始化为其默认值0,然后在步骤4中设置为1。
Eric Lippert的文章系列Why do initializers run in the opposite order as constructors, part 1,part 2中的更多信息。
答案 2 :(得分:3)
区别在于构造函数调用和'a'字段设置之间的顺序,正如您在IL中可以看到的每个类:
Class1
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: stfld int32 SandBox.Class1::a
IL_0007: ldarg.0
IL_0008: call instance void [mscorlib]System.Object::.ctor()
IL_000d: ret
<强>的Class2 强>
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: ldc.i4.1
IL_0008: stfld int32 SandBox.Class2::a
IL_000d: ret
答案 3 :(得分:1)
您不能对每个字段或自动属性使用初始化。构造函数使您能够为这些字段和属性设置值。
应该注意的是,字段初始化是在类中的每个构造函数之前,所以编写一个默认构造函数(并且让一个类的所有其他构造函数从它继续)可能是从代码大小的角度来看,效率更高。这是一种默认构造函数可以派上用场的方式。
答案 4 :(得分:1)
在您的具体示例中,字段初始值设定项(Class1
)没问题。可以说,不是的是公共领域; p我会建议:
// manually implemented property with field-initializer
private int a = 1;
public int A { get { return a;} set { a = value;} }
或:
// automatically implemented property with constructor-based initialization
public int A {get;set;}
public Class1() {
A = 1;
}
@hvd's answer正确地说明了区别。为了说明这可以给出不同结果的具体示例,请参阅以下内容。这个示例中的主要收集消息实际上是“在使用构造函数的virtual
方法时非常小心”。
先输出:
Class1: 1
Class2: 0
代码:
using System;
abstract class SomeBaseClass {
protected abstract void Write();
protected SomeBaseClass() {
Console.Write(GetType().Name + ": ");
Write();
}
}
class Class1 : SomeBaseClass {
protected override void Write() {
Console.WriteLine(a);
}
public int a = 1;
}
class Class2 : SomeBaseClass {
protected override void Write() {
Console.WriteLine(a);
}
public int a;
public Class2() {
a = 1;
}
}
static class Program {
static void Main() {
new Class1();
new Class2();
}
}