这两者有什么区别?
class Class1
{
public int a = 1;
}
class Class2
{
public int a;
public Class2()
{
a = 1;
}
}
如果没有,我可以跳过默认构造函数并初始化我的变量Class1
吗?
这两者有什么区别?
class Class1
{
public int a = 1;
}
class Class2
{
public int a;
public Class2()
{
a = 1;
}
}
如果没有,我可以跳过默认构造函数并初始化我的变量Class1
吗?
调用new Class1()
首先设置a
为1
,然后调用基类构造函数。
调用new Class2()
首先调用基类构造函数,然后设置a
为1
.
由于您是从 派生的object
,因此基类构造函数什么也不做。在其他情况下,它可能会有所作为。
您不会注意到代码中的差异,但差异在于调用和初始化事物的顺序:
因此,在您Class1
的字段在步骤 1 中初始化。在您Class2
的字段在步骤 1 中初始化为其默认值 0,然后在步骤 4 中设置为 1。
更多信息请参阅 Eric Lippert 的文章系列为什么初始化程序以与构造函数相反的顺序运行,第 1部分,第 2 部分。
区别在于构造函数调用和“a”字段设置之间的顺序,正如您在每个类的 IL 中看到的那样:
第一类
.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
2 类
.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
在您的具体示例中,字段初始值设定项 ( 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 的回答正确地说明了差异。为了说明一个具体的例子来说明这会产生不同的结果,请参见以下内容。这个例子的主要信息是“在使用构造函数的方法时要非常小心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();
}
}
您不能对每个字段或自动属性都使用初始化。构造函数使您能够为这些字段和属性设置值。
应该注意的是,字段初始化是附加在类中的每个构造函数之前的,所以从代码大小的角度来看,编写一个默认构造函数(并让一个类的所有其他构造函数从它继续)可能更有效。这是默认构造函数真正派上用场的一种方式。