C#成员变量初始化;最佳实践?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/298183/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# member variable initialization; best practice?
提问by Steve Crane
Is it better to initialize class member variables on declaration
在声明时初始化类成员变量是否更好
private List<Thing> _things = new List<Thing>();
private int _arb = 99;
or in the default constructor?
还是在默认构造函数中?
private List<Thing> _things;
private int _arb;
public TheClass()
{
_things = new List<Thing>();
_arb = 99;
}
Is it simply a matter of style or are there performance trade-offs, one way or the other?
这仅仅是风格问题还是性能权衡,以一种或另一种方式?
采纳答案by Marc Gravell
In terms of performance, there is no real difference; field initializers are implemented as constructor logic. The only difference is that field initializers happen before any "base"/"this" constructor.
在性能方面,没有真正的区别;字段初始值设定项实现为构造函数逻辑。唯一的区别是字段初始值设定项发生在任何“base”/“this”构造函数之前。
The constructor approach can be used with auto-implemented properties (field initializers cannot) - i.e.
构造函数方法可以与自动实现的属性一起使用(字段初始值设定项不能) - 即
[DefaultValue("")]
public string Foo {get;set;}
public Bar() { // ctor
Foo = "";
}
Other than that, I tend to prefer the field initializer syntax; I find it keeps things localized - i.e.
除此之外,我倾向于更喜欢字段初始值设定项语法;我发现它使事情本地化 - 即
private readonly List<SomeClass> items = new List<SomeClass>();
public List<SomeClass> Items {get {return items;}}
I don't have to go hunting up and down to find where it is assigned...
我不必四处寻找它被分配的地方......
The obvious exception is where you need to perform complex logic or deal with constructor parameters - in which case constructor-based initialization is the way to go. Likewise, if you have multiple constructors, it would be preferable for the fields to always get set the same way - so you might have ctors like:
明显的例外是您需要执行复杂的逻辑或处理构造函数参数 - 在这种情况下,基于构造函数的初始化是要走的路。同样,如果您有多个构造函数,则最好始终以相同的方式设置字段 - 所以您可能有像这样的构造函数:
public Bar() : this("") {}
public Bar(string foo) {Foo = foo;}
edit: as a side comment, note that in the above, if there are other fields (not shown) with field initializers, then they are only directly initialized in the constructors that call base(...)
- i.e. the public Bar(string foo)
ctor. The other constructor does notrun field initializers, since it knows they are done by the this(...)
ctor.
编辑:作为旁注,请注意,在上面,如果有其他字段(未显示)带有字段初始值设定项,则它们仅在调用的构造函数中直接初始化base(...)
- 即public Bar(string foo)
ctor。另一个构造函数不运行字段初始值设定项,因为它知道它们是由构造函数完成的this(...)
。
回答by Kent Boogaart
For instance variables, it is largely a matter of style (I prefer using a constructor). For static variables, there is a performance benefitto initializing inline (not always possible, of course).
例如变量,这主要是风格问题(我更喜欢使用构造函数)。对于静态变量,内联初始化具有性能优势(当然,并非总是可行)。
回答by Nico
It's really up to you.
I often initialize them inline, cause I don't like having a constructor when I don't really need one (I like small classes !).
这真的取决于你。
我经常内联初始化它们,因为当我真的不需要构造函数时我不喜欢有一个构造函数(我喜欢小类!)。
回答by Tor Haugen
Actually, field initializers as you demonstrate is a convenient shorthand. The compiler actually copies the initialization code into the beginning of each instance constructor that you define for your type.
实际上,您演示的字段初始值设定项是一种方便的速记。编译器实际上将初始化代码复制到您为类型定义的每个实例构造函数的开头。
This has two implications: first, any field initialization code is duplicated in each constructor and, second, any code you include in your constructors to initialize fields to specific values will in fact re-assign the fields.
这有两个含义:首先,任何字段初始化代码在每个构造函数中都重复,其次,您在构造函数中包含的用于将字段初始化为特定值的任何代码实际上都会重新分配字段。
So performance-wise, and with regards to compiled code size, you're better off moving field initializers into constructors.
因此,在性能方面,以及编译代码大小方面,您最好将字段初始值设定项移动到构造函数中。
On the other hand, the performance impact and code 'bloat' will usually be negligable, and the field initializer syntax has the important benefit of lessening the risk that you might forget to initialize some field in one of your constructors.
另一方面,性能影响和代码“膨胀”通常可以忽略不计,并且字段初始值设定项语法具有降低您可能忘记在构造函数中初始化某些字段的风险的重要好处。
回答by GeekyMonkey
Use either field initializers or create an Init() function. The problem with putting these things in your constructor is that if you ever need to add a 2nd constructor, you end up with copy/paste code (or you overlook it and end up with uninitialized variables).
使用字段初始值设定项或创建 Init() 函数。将这些东西放在构造函数中的问题在于,如果您需要添加第二个构造函数,最终会得到复制/粘贴代码(或者您忽略它并最终得到未初始化的变量)。
I would either initialize where declared. Or have the constructor(s) call an Init() function.
我要么在声明的地方初始化。或者让构造函数调用 Init() 函数。
回答by supercat
One major limitation with field initializers is that there's no way to wrap them in a try-finally block. If an exception is thrown in a field initializer, any resources that were allocated in previous initializers will be abandoned; there's no way to prevent it. Other errors in construction can be dealt with, if awkwardly, by having a protected base constructor accept an IDisposable by reference, and pointing it at itself as its very first operation. One can then avoid calling the constructor except through factory methods which in case of exception will call Dispose on the partially-created object. This protection will allow for cleanup of IDisposables created in derived-class initializers if the main-class constructor fails after "smuggling out" a reference to the new object. Unfortunately, there's no way to provide such protection if a field initializer fails.
字段初始值设定项的一个主要限制是无法将它们包装在 try-finally 块中。如果在字段初始值设定项中抛出异常,则在先前初始值设定项中分配的任何资源都将被放弃;没有办法阻止它。构造中的其他错误可以通过让受保护的基构造函数通过引用接受 IDisposable 并将其作为它的第一个操作指向自身来处理,如果笨拙的话。然后可以避免调用构造函数,除非通过工厂方法,在异常情况下将调用部分创建的对象上的 Dispose。如果主类构造函数在“走私”对新对象的引用后失败,则此保护将允许清除在派生类初始值设定项中创建的 IDisposable。不幸的是,有'
回答by Qubits
On added point to the above - You always have a constructor when implementing classes that have an implementation. If you do not declare one then the default instructor is inferred by the compiler [public Foo(){}]; a constructor that takes no arguments.
关于上面的补充点 - 在实现具有实现的类时,您总是有一个构造函数。如果您不声明,则编译器会推断默认讲师 [public Foo(){}]; 一个不带参数的构造函数。
Often times I like to offer both approaches. Allow constructors for those that wish to use them and allow the Field Initializers for situations where you wish to use a simplified or default implementation of your class / type. This adds flexibility to your code. Keep in mind that anyone can use the default field initializer if they choose ... be sure to declare it manually if you offer more than one constructor - public Foo(){}
很多时候我喜欢提供这两种方法。允许那些希望使用它们的构造函数,并允许 Field Initializers 用于您希望使用类/类型的简化或默认实现的情况。这为您的代码增加了灵活性。请记住,任何人都可以选择使用默认字段初始值设定项……如果您提供多个构造函数,请务必手动声明它 - public Foo(){}