3

这两者有什么区别?

class Class1
{
    public int a = 1;
}

class Class2
{
    public int a;
    public Class2()
    {
        a = 1;
    }
}

如果没有,我可以跳过默认构造函数并初始化我的变量Class1吗?

4

5 回答 5

8

调用new Class1()首先设置a1,然后调用基类构造函数。

调用new Class2()首先调用基类构造函数,然后设置a1.

由于您是从 派生的object,因此基类构造函数什么也不做。在其他情况下,它可能会有所作为。

于 2013-05-20T13:52:07.343 回答
8

您不会注意到代码中的差异,但差异在于调用和初始化事物的顺序:

  1. 派生类字段初始化程序运行。
  2. 基类字段初始化程序运行。
  3. 基类构造函数运行。
  4. 派生类构造函数运行。

因此,在您Class1的字段在步骤 1 中初始化。在您Class2的字段在步骤 1 中初始化为其默认值 0,然后在步骤 4 中设置为 1。

更多信息请参阅 Eric Lippert 的文章系列为什么初始化程序以与构造函数相反的顺序运行,第 1部分,第 2 部分

于 2013-05-20T13:54:06.973 回答
3

区别在于构造函数调用和“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
于 2013-05-20T14:01:35.353 回答
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 的回答正确地说明了差异。为了说明一个具体的例子来说明这会产生不同的结果,请参见以下内容。这个例子的主要信息是“在使用构造函数的方法时要非常小心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();
    }
}
于 2013-05-20T13:58:45.523 回答
1

您不能对每个字段或自动属性都使用初始化。构造函数使您能够为这些字段和属性设置值。

应该注意的是,字段初始化是附加在类中的每个构造函数之前的,所以从代码大小的角度来看,编写一个默认构造函数(并让一个类的所有其他构造函数从它继续)可能更有效。这是默认构造函数真正派上用场的一种方式。

于 2013-05-20T13:53:23.227 回答