複数 - c# デフォルトコンストラクタ 省略




コンストラクタまたは宣言時にクラスフィールドを初期化しますか? (10)

1つ注意点があると思います。 私はかつてそのようなエラーをコミットしました。派生クラスの内部で、抽象基本クラスから継承されたフィールドを「宣言で初期化する」ことを試みました。 その結果、2つのフィールドセットがありました。1つは「ベース」、もう1つは新しく宣言されたフィールドで、デバッグにかなり時間がかかりました。

レッスン: 継承された フィールドを初期化するために、あなたはそれをコンストラクタの中でするでしょう。

私は最近C#とJavaでプログラミングをしてきましたが、クラスフィールドを初期化することが最も良い場所であることに興味があります。

宣言時にそれを行うべきですか?

public class Dice
{
    private int topFace = 1;
    private Random myRand = new Random();

    public void Roll()
    {
       // ......
    }
}

それともコンストラクタの中で?

public class Dice
{
    private int topFace;
    private Random myRand;

    public Dice()
    {
        topFace = 1;
        myRand = new Random();
    }

    public void Roll()
    {
        // .....
    }
}

私はあなたの何人かのベテランがベストプラクティスであると思うものに本当に興味があります。 私は一貫性を保ち、一つのアプローチに固執したい


C#では問題ありません。 あなたが与える2つのコードサンプルは全く同等です。 最初の例では、C#コンパイラ(またはCLRですか?)が空のコンストラクタを構築し、あたかもそれらがコンストラクタ内にあるかのように変数を初期化します(Jon Skeetが以下のコメントで説明していることに微妙な違いがあります)。 すでにコンストラクタがある場合は、「上」の初期化はその先頭に移動します。

ベストプラクティスに関しては、誰かが別のコンストラクタを簡単に追加してそれをチェーニングすることを忘れる可能性があるため、前者は後者よりもエラーが少ない傾向があります。


C#の設計は、インライン初期化が優先されること、またはそれが言語に含まれないことを示唆しています。 コード内の異なる場所間の相互参照を避けることができるときはいつでも、あなたは一般的にお勧めです。

最高のパフォーマンスを引き出すにはインラインである必要がある静的フィールドの初期化との一貫性の問題もあります。 コンストラクタ設計の ためのフレームワーク設計ガイドラインはこう言います:

✓ランタイムは明示的に定義された静的コンストラクタを持たない型のパフォーマンスを最適化できるため、静的コンストラクタを明示的に使用するのではなくインラインで静的フィールドを初期化します。

この文脈で「考える」とは、理由がない限り、そうすることを意味します。 静的初期化子フィールドの場合、初期化が複雑すぎてインラインでコーディングすることができない場合には、それがもっともな理由です。


Javaでは、宣言付きの初期化子は、どのコンストラクタが使用されているか(複数ある場合)、またはコンストラクタのパラメータ(引数がある場合)に関係なく、フィールドは常に同じ方法で初期化されます。値を変更します(それがfinalではない場合)。 したがって、宣言付きでイニシャライザを使用すると、どのコンストラクタが使用されているかに関係なく、またコンストラクタに渡されるパラメータに関係なく、初期化された値が すべての場合に フィールドが持つ値であることがわかります。 したがって、すべての構成されたオブジェクトの値が同じである場合に限り、また常にそうである場合に限り、宣言で初期化指定子を使用してください。


あなたの例で型を仮定すると、間違いなくコンストラクタ内のフィールドを初期化することを好む。 例外的なケースは次のとおりです。

  • 静的クラス/メソッド内のフィールド
  • static / final / etと入力されたフィールド

私はいつもクラスのトップにあるフィールドリストを目次(ここに含まれているのは使われているのではなく)として、そしてコンストラクタを紹介として考えています。 方法はもちろん章です。


さまざまな状況があります。

空のリストが必要です

状況は明らかです。 私は自分のリストを準備し、誰かがリストに項目を追加したときに例外がスローされないようにするだけです。

public class CsvFile
{
    private List<CsvRow> lines = new List<CsvRow>();

    public CsvFile()
    {
    }
}

私は価値を知っています

デフォルトでどのような値を設定したいのか、または他のロジックを使用する必要があるのか​​、正確にわかっています。

public class AdminTeam
{
    private List<string> usernames;

    public AdminTeam()
    {
         usernames = new List<string>() {"usernameA", "usernameB"};
    }
}

または

public class AdminTeam
{
    private List<string> usernames;

    public AdminTeam()
    {
         usernames = GetDefaultUsers(2);
    }
}

可能な値を持つ空のリスト

他のコンストラクタを通して値を追加する可能性があるので、デフォルトで空のリストを期待することがあります。

public class AdminTeam
{
    private List<string> usernames = new List<string>();

    public AdminTeam()
    {
    }

    public AdminTeam(List<string> admins)
    {
         admins.ForEach(x => usernames.Add(x));
    }
}

宣言に値を設定すると、パフォーマンスがわずかに向上します。 コンストラクタで設定した場合、実際には2回設定されます(最初はデフォルト値に設定され、次にctorでリセットされます)。


私があなたに言った場合、どうなりますか?

私は一般的にすべてを初期化し、一貫した方法でそれを行います。 はい、それは過度に明白ですが、それはまた維持することがもう少し簡単です。

私たちがパフォーマンスを心配しているのであれば、私はしなければならないことだけを初期化して、それがそれが支出のために最も強打を与える領域にそれを配置することです。

リアルタイムシステムでは、変数または定数さえも必要なのかどうか、私は疑問に思います。

そしてC ++では、どちらの場所でも初期化なしの次に実行し、それをInit()関数に移動します。 どうして? C ++では、オブジェクトの構築中に例外をスローする可能性があるものを初期化していると、メモリリークが発生します。


私は通常、コンストラクタに依存関係を取得し、それに関連するインスタンスメンバを初期化すること以外何もしないようにします。 あなたがあなたのクラスをユニットテストしたいなら、これはあなたの人生を楽にするでしょう。

インスタンス変数に代入しようとしている値が、コンストラクタに渡す予定のパラメータの影響を受けない場合は、宣言時に代入してください。


ベストプラクティス について あなたの質問に対する直接的な答えではありませんが、重要で関連する新たなポイントは、ジェネリッククラス定義の場合、デフォルト値で初期化するためにコンパイラに任せるか、フィールドを初期化する特別な方法を使わなければならないということですそれらのデフォルト値にしてください(それがコードの可読性のために絶対に必要な場合)。

class MyGeneric<T>
{
    T data;
    //T data = ""; // <-- ERROR
    //T data = 0; // <-- ERROR
    //T data = null; // <-- ERROR        

    public MyGeneric()
    {
        // All of the above errors would be errors here in constructor as well
    }
}

汎用フィールドをデフォルト値に初期化するための特別な方法は次のとおりです。

class MyGeneric<T>
{
    T data = default(T);

    public MyGeneric()
    {           
        // The same method can be used here in constructor
    }
}




java