C#成员变量初始化; 最佳实践?

Ste*_*ane 92 c# constructor declaration

在声明上初始化类成员变量是否更好?

private List<Thing> _things = new List<Thing>();
private int _arb = 99;
Run Code Online (Sandbox Code Playgroud)

还是在默认构造函数中?

private List<Thing> _things;
private int _arb;

public TheClass()
{
  _things = new List<Thing>();
  _arb = 99;
}
Run Code Online (Sandbox Code Playgroud)

这仅仅是一种风格问题,还是存在性能权衡,这种或那种方式?

Mar*_*ell 77

在性能方面,没有真正的区别; 字段初始值设定项实现为构造函数逻辑.唯一的区别是字段初始化器发生在任何"base"/"this"构造函数之前.

构造函数方法可以与自动实现的属性一起使用(字段初始化器不能) - 即

[DefaultValue("")]
public string Foo {get;set;}
public Bar() { // ctor
  Foo = "";
}
Run Code Online (Sandbox Code Playgroud)

除此之外,我倾向于选择字段初始化语法; 我发现它可以保持本地化 - 即

private readonly List<SomeClass> items = new List<SomeClass>();
public List<SomeClass> Items {get {return items;}}
Run Code Online (Sandbox Code Playgroud)

我不必上下打猎找到它的分配地点......

明显的例外是您需要执行复杂逻辑或处理构造函数参数 - 在这种情况下,基于构造函数的初始化是最佳选择.同样,如果你有多个构造函数,那么最好总是以相同的方式设置字段 - 所以你可能会喜欢:

public Bar() : this("") {}
public Bar(string foo) {Foo = foo;}
Run Code Online (Sandbox Code Playgroud)

编辑:作为旁注,请注意,在上面,如果有其他字段(未显示)与字段初始值设定项,那么它们只在调用的构造函数中直接初始化base(...)- 即public Bar(string foo)ctor.另一个构造函数运行字段初始值设定项,因为它知道它们是由this(...)ctor 完成的.


Tor*_*gen 10

实际上,您演示的字段初始化程序是一种方便的简写.编译器实际上将初始化代码复制到您为类型定义的每个实例构造函数的开头.

这有两个含义:第一,任何字段初始化代码在每个构造函数中都是重复的,第二,您在构造函数中包含的用于将字段初始化为特定值的任何代码实际上都会重新分配字段.

因此在性能方面,关于编译代码大小,最好将字段初始化器移动到构造函数中.

另一方面,性能影响和代码'膨胀'通常是可以忽略的,并且字段初始化程序语法具有减少您可能忘记在其中一个构造函数中初始化某些字段的风险的重要好处.

  • 性能点仅适用于重新分配值(即它不适用于原始代码).同样,"膨胀"问题(这是微不足道的)仅适用于调用base(...)的ctors - 因此你可以使用私有ctor(如已发布)来支持这一点 - 只有这个ctor才会启动字段. (2认同)

sup*_*cat 6

字段初始值设定项的一个主要限制是无法将它们包装在 try-finally 块中。如果在字段初始值设定项中抛出异常,则在先前初始值设定项中分配的任何资源都将被放弃;没有办法阻止它。构造中的其他错误可以通过让受保护的基构造函数通过引用接受 IDisposable 并将其作为它的第一个操作指向自身来处理,如果笨拙的话。然后可以避免调用构造函数,除非通过工厂方法,在异常的情况下,将在部分创建的对象上调用 Dispose。如果主类构造函数在“走私”对新对象的引用后失败,则此保护将允许清除在派生类初始值设定项中创建的 IDisposable。不幸的是,有'