102

宣言時にクラスメンバー変数を初期化する方が良いですか

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;
}

それは単にスタイルの問題ですか、それともパフォーマンスのトレードオフがありますか?

4

7 に答える 7

84

パフォーマンスに関しては、実質的な違いはありません。フィールド初期化子は、コンストラクター ロジックとして実装されます。唯一の違いは、フィールド初期化子が「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;}}

割り当てられている場所を見つけるためにあちこち探し回る必要はありません...

明らかな例外は、複雑なロジックを実行したり、コンストラクターのパラメーターを処理したりする必要がある場合です。この場合、コンストラクター ベースの初期化が適しています。同様に、複数のコンストラクターがある場合は、フィールドが常に同じ方法で設定されることが望ましいため、次のような ctor を使用できます。

public Bar() : this("") {}
public Bar(string foo) {Foo = foo;}

編集:サイドコメントとして、上記で、フィールド初期化子を持つ他のフィールド(表示されていない)がある場合、それらは呼び出すコンストラクター、base(...)つまりpublic Bar(string foo)ctorでのみ直接初期化されることに注意してください。他のコンストラクターは、フィールド初期化子がctorによって実行されることを認識しているため、それらを実行しません。this(...)

于 2008-11-18T09:04:34.293 に答える
13

実際、あなたが示すように、フィールド初期化子は便利な省略形です。コンパイラは、実際には、型に対して定義した各インスタンス コンストラクターの先頭に初期化コードをコピーします。

これには 2 つの意味があります。1 つ目は、フィールド初期化コードが各コンストラクターで複製されることです。2 つ目は、フィールドを特定の値に初期化するためにコンストラクターに含めるコードは、実際にはフィールドを再割り当てします。

したがって、パフォーマンスとコンパイルされたコードのサイズに関しては、フィールド初期化子をコンストラクターに移動した方がよいでしょう。

一方、パフォーマンスへの影響とコードの「肥大化」は通常は無視できる程度であり、フィールド初期化構文には、コンストラクターの 1 つで一部のフィールドを初期化するのを忘れるリスクを軽減するという重要な利点があります。

于 2008-11-18T09:12:22.670 に答える
6

フィールド初期化子の主な制限の1つは、それらをtry-finallyブロックでラップする方法がないことです。フィールド初期化子で例外がスローされた場合、以前の初期化子で割り当てられたリソースはすべて破棄されます。それを防ぐ方法はありません。構築における他のエラーは、厄介な場合は、保護されたベースコンストラクターに参照によってIDisposableを受け入れさせ、それ自体を最初の操作として指定することで対処できます。そうすれば、例外の場合に部分的に作成されたオブジェクトに対してDisposeを呼び出すファクトリメソッドを除いて、コンストラクタを呼び出さないようにすることができます。この保護により、新しいオブジェクトへの参照を「密輸」した後にメインクラスのコンストラクターが失敗した場合に、派生クラスの初期化子で作成されたIDisposableをクリーンアップできます。残念ながら、

于 2011-03-18T17:22:37.073 に答える
3

インスタンス変数の場合、それは主にスタイルの問題です (私はコンストラクターを使用することを好みます)。静的変数の場合、インラインで初期化するとパフォーマンスが向上します (もちろん、常に可能というわけではありません)。

于 2008-11-18T08:58:17.643 に答える
3

フィールド初期化子を使用するか、Init() 関数を作成します。これらのものをコンストラクターに入れることの問題は、2 番目のコンストラクターを追加する必要がある場合に、コードをコピーして貼り付けてしまうことです (または、それを見落として、初期化されていない変数になってしまいます)。

宣言された場所を初期化します。または、コンストラクターで Init() 関数を呼び出すようにします。

于 2008-11-18T09:45:15.583 に答える
1

それは本当にあなた次第です。
私はしばしばそれらをインラインで初期化します。なぜなら、本当に必要でないときにコンストラクターを持つのが好きではないからです (私は小さなクラスが好きです!)。

于 2008-11-18T09:04:24.387 に答える
0

上記に加えて-実装を持つクラスを実装するときは、常にコンストラクターがあります。宣言しない場合、デフォルトのインストラクターはコンパイラーによって推測されます[public Foo(){}]; 引数を取らないコンストラクター。

多くの場合、私は両方のアプローチを提供したいと思います。それらを使用したいコンストラクターを許可し、クラス/タイプの単純化された実装またはデフォルトの実装を使用したい状況でフィールド初期化子を許可します。これにより、コードに柔軟性が追加されます。選択した場合、誰でもデフォルトのフィールド初期化子を使用できることに注意してください...複数のコンストラクターを提供する場合は、必ず手動で宣言してください--public Foo(){}

于 2012-02-06T11:46:58.190 に答える