字段初始化

以下两种字段初始化方式之间是否存在差异? 什么时候使用哪一个?

第一种方式

public class Class1 { private SomeClass someclass; public Class1() { someclass = new SomeClass(some arg); } } 

第二种方式

 public class Class1 { private SomeClass someclass = new SomeClass(some arg); } 

第二个例子中的字段可以是只读的。

初始化内联字段时,不能使用this关键字。 这样做的原因是代码的执行顺序:对于所有意图和目的,初始化字段内联的代码在类的构造函数之前运行(即C#编译器将阻止访问this关键字)。 基本上这意味着这将无法编译:

 public class Class1 { private SomeClass someclass = new SomeClass(this); public Class1() { } } 

但这会:

 public class Class1 { private SomeClass someclass; public Class1() { someclass = new SomeClass(this); } } 

这是一个微妙的差异,但值得注意的是。

两个版本之间的其他差异在使用inheritance时才非常明显。 如果你有两个相互inheritance的类,那么首先初始化派生类中的字段,然后初始化基类中的字段,然后调用基类的构造函数,最后是构造函数。将调用派生类。 在某些情况下你需要非常小心,因为如果你没有意识到发生了什么,它可能会导致水果沙拉的混乱(其中一个涉及在基类构造函数中调用虚方法,但是几乎从来都不是一个明智的举动)。 下面是一个例子:

 class BaseClass { private readonly object objectA = new object(); // Second private readonly object objectB; public BaseClass() { this.objectB = new object(); // Third } } class DerivedClass : BaseClass { private object objectC = new object(); // First private object objectD; public DerivedClass() { this.objectD = new object(); // Forth } } 

您需要在初始化字段的所有行上设置断点,以便能够查看正确的序列。

存在一个细微的差别,因为第二个示例中的字段将在基类中的字段初始化之前初始化,并且第一个示例中的字段将在之后初始化。 然而,这很少有任何影响。

这主要是风格和偏好的问题。 我个人更喜欢第二个,因为它使构造函数更清晰,可用于更多基于逻辑的初始化,但有一个强有力的理由可以在构造函数中完成所有初始化。

为了完整起见,初始化顺序如下:

  1. 静态字段
  2. 静态构造函数
  3. 实例字段
  4. 基本静态字段
  5. 基础静态构造函数
  6. 基本实例字段
  7. 基础构造函数
  8. 构造函数

除了代码行数之外,还有细微差别。

例如,字段初始化在构造函数运行之前发生。 在你的例子中没有太大的区别,但要记住。

我会将第二个示例中的字段初始化保留为简单的(字符串或整数),以避免在初始化期间发生可能的exception。

如上所述,在两种方式中,字段都可以只读,因为只能在构造期间写入只读字段。

实际上,这两个类中的字段都可以是只读的。

有区别。

想象一下,你有一个包含多个构造函数的类。 使用第一种方法,每个构造函数都需要创建这些对象。 这可能是预期的行为,因为您可能希望每次都以不同方式创建对象。 对构造函数的这个额外责任可能是一件坏事,因为如果你不记得在每个构造函数中初始化变量,那么你最终会得到一个null对象。

要考虑的效率很小,但它并不重要 – 第一种方式需要两个赋值,首先是null,然后是创建的对象,而第二种方式是对象在一步中创建和初始化。

然后考虑静态变量。 静态变量必须以第二种方式声明,因为永远不会保证会创建类的实例。

由于exception管理和调试商品,建议使用构造方法。

如果一个字段应该是readonly,你可以声明一个readonly属性(这只有getter)。

类的实例字段变量初始值设定项对应于在进入该类的任何一个实例构造函数时立即执行的赋值序列。 变量初始值设定项以它们出现在类声明中的文本顺序执行。

实例字段的变量初始值设定项无法引用正在创建的实例。 因此,在变量初始化程序中引用它是一个编译时错误,因为变量初始化程序通过简单名称引用任何实例成员是编译时错误。

所有字段都会进行默认值初始化 ,包括具有可变初始值设定项的字段。 因此,当初始化类时,首先将该类中的所有静态字段初始化为其默认值,然后以文本顺序执行静态字段初始值设定项。 同样,当创建类的实例时,首先将该实例中的所有实例字段初始化为其默认值,然后以文本顺序执行实例字段初始化程序。

如果你的“some arg”参数不是静态的,那么第一个是有用的。 如果只能通过构造函数获得该参数,那么这就是采用的方法。 第二种方式出现问题。 如果在SomeClass的实例化期间抛出exception,则无法在Class1中捕获该exception。

最好的祝愿,
法比安

差别很小。 编译器将按照定义的顺序将所有内联初始值设定项放在构造函数的开头。

如果需要复杂的逻辑来初始化字段,您可能希望使用构造函数方法,否则我认为内联方法更清晰,更易于维护,因为编译器会为您调用它。

实际上我更喜欢第二个的可读性和易于调试,你可以通过try catch包装调用,但在第一个你不能。