C#成员variables的初始化 最佳实践?
在声明上初始化类成员variables是否更好?
private List<Thing> _things = new List<Thing>(); private int _arb = 99;
或者在默认的构造函数?
private List<Thing> _things; private int _arb; public TheClass() { _things = new List<Thing>(); _arb = 99; }
这只是一个风格问题,还是存在性能平衡,无论哪种方式?
在performance方面,没有真正的区别; 字段初始值设定项被实现为构造函数逻辑。 唯一的区别是字段初始值设定项在任何“base”/“this”构造函数之前发生。
构造函数的方法可以使用自动实现的属性(字段初始值不能) – 即
[DefaultValue("")] public string Foo {get;set;} public Bar() { // ctor Foo = ""; }
除此之外,我倾向于更喜欢字段初始值设定语法; 我发现它保持本地化 – 即
private readonly List<SomeClass> items = new List<SomeClass>(); public List<SomeClass> Items {get {return items;}}
我不必上下寻找它在哪里被分配…
明显的例外是你需要执行复杂的逻辑或处理构造函数参数的地方 – 在这种情况下,基于构造函数的初始化就是要走的路。 同样,如果你有多个构造函数,那么这个字段最好总是以相同的方式设置 – 所以你可能有如下的ctors:
public Bar() : this("") {} public Bar(string foo) {Foo = foo;}
编辑:作为一个方面的评论,请注意,在上面,如果有其他字段(未显示)与字段初始值设定项,那么他们只是直接初始化在构造函数调用base(...)
– 即public Bar(string foo)
ctor。 另一个构造函数不会运行字段初始值设定项,因为它知道它是由this(...)
ctor完成的。
实际上,你演示的字段初始值是一个方便的速记。 编译器实际上将初始化代码复制到为您的types定义的每个实例构造函数的开头。
这有两个含义:第一,任何字段初始化代码都在每个构造函数中重复,其次,您在构造函数中包含的任何代码将字段初始化为特定值,实际上将重新分配字段。
所以在性能方面,对于编译的代码大小,最好将字段初始值设定项移动到构造函数中。
另一方面,性能影响和代码“膨胀”通常是可以忽略的,字段初始值设定器语法对于减less您可能忘记初始化某个构造函数中某些字段的风险具有重要的好处。
字段初始化程序的一个主要限制是无法将它们封装在try-finally块中。 如果在字段初始值设定项中引发exception,则将放弃在以前的初始值设定项中分配的任何资源; 没有办法阻止它。 构造中的其他错误可以通过让受保护的基构造器通过引用接受一个IDisposable来处理,如果它笨拙的话,可以把它指向它自己作为它的第一个操作。 然后可以避免调用构造函数,除非通过工厂方法,在exception的情况下将调用Dispose部分创build的对象。 如果主类构造函数在“走私”引用新对象之后失败,则此保护将允许清除在派生类初始化程序中创build的IDisposables。 不幸的是,如果字段初始值设定项失败,则无法提供这种保护。
使用字段初始值设定项或创build一个Init()函数。 将这些东西放在构造函数中的问题是,如果您需要添加第二个构造函数,则最终会使用复制/粘贴代码(或者忽略它,最终导致未初始化的variables)。
我要么初始化在哪里宣布。 或者让构造函数调用一个Init()函数。
例如variables,这主要是一个风格问题(我更喜欢使用构造函数)。 对于静态variables,初始化内联(当然不总是可能的)会带来性能上的好处 。
这真的取决于你。
我经常将它们初始化为内联,因为当我不需要构造函数时(我喜欢小类),我不喜欢有构造函数。
关于上面的添加点 – 实现具有实现的类时总是有一个构造函数。 如果你不声明一个,那么编译器[public Foo(){}]推断默认的讲师。 一个没有参数的构造函数。
我经常喜欢提供这两种方法。 允许那些希望使用它们的构造函数,并允许Field Initializer用于你希望使用类/types的简化或默认实现的情况。 这增加了您的代码的灵活性。 请记住,任何人都可以使用默认字段初始值设定项,如果他们select的话…如果您提供了多个构造函数,一定要手动声明它 – public Foo(){}