C# member variable initialization; best practice?

2019-01-01 10:59发布

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?

7条回答
骚的不知所云
2楼-- · 2019-01-01 11:10

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.

查看更多
爱死公子算了
3楼-- · 2019-01-01 11:15

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.

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 not run field initializers, since it knows they are done by the this(...) ctor.

查看更多
人气声优
4楼-- · 2019-01-01 11:25

For instance variables, it is largely a matter of style (I prefer using a constructor). For static variables, there is a performance benefit to initializing inline (not always possible, of course).

查看更多
公子世无双
5楼-- · 2019-01-01 11:27

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 !).

查看更多
余欢
6楼-- · 2019-01-01 11:30

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.

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(){}

查看更多
素衣白纱
7楼-- · 2019-01-01 11:31

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).

I would either initialize where declared. Or have the constructor(s) call an Init() function.

查看更多
登录 后发表回答