3

クラスを設計するとき、クラスフィールドの初期化に関するガイドラインはありますか?初期化には2つの別々の方法があります。インラインフィールド初期化子を使用することも、コンストラクターで初期化することもできます。さらに興味深いことに、静的フィールドが導入されると、定義時にフィールドを初期化できるか、静的コンストラクター、またはフィールドが既に設定されているかどうかを確認するインスタンスコンストラクターでフィールドを初期化できます。工場が導入されると、これはさらに混乱します。

例1-インライン初期化


    public class ExampleOne
    {
        private readonly IDictionary _collection = new Dictionary();

        ...
    }       

例2-コンストラクタの初期化


    public class ExampleTwo
    {
        private readonly IDictionary _collection;

        public ExampleTwo() 
        {
            _collection = new Dictionary();
        }
        ...
    }       

例3-静的インライン初期化


    public class ExampleThree
    {
        private static readonly IDictionary __collection = new Dictionary();

        ...
    }       

例4-静的コンストラクタの初期化


    public class ExampleFour
    {
        private static IDictionary __collection;

        static ExampleFour() 
        {
            _collection = new Dictionary();
        }

        ...
    }       

例5-静的/インスタンスコンストラクターミックスの初期化


    public class ExampleFive
    {
        private static readonly IDictionary __collection;
        private static IDictionary __anotherCollection;

        static ExampleFive() 
        {
            _collection = new Dictionary();
        }

        public ExampleFive()
        {
           if( __anotherCollection == null ) 
           {
            __anotherCollection = new Dictionary();
           }
        }

        ...
    }       

例6-ファクトリメソッド


    public class ExampleSix
    {
        private static readonly IDictionary __collection;
        private static IDictionary __anotherCollection;

        static ExampleSix() 
        {
            _collection = new Dictionary();
        }

        public static ExampleSix Create()
        {
           if( __anotherCollection == null ) 
           {
            __anotherCollection = new Dictionary();
           }

           var example = new ExampleSix();
           return example;
        }

        ...
    }       

現在、私が持っているクラスはこれらすべてを混ぜる傾向があります。インスタンスコンストラクターで静的フィールドを設定することは避けようとしましたが。

例7-混合


    public class ExampleSeven
    {
        private static readonly IDictionary __collection = new Dictionary();
        private static readonly IDictionary __anotherCollection;
        private static readonly IDictionary __thirdCollection;
        private static IDictionary __fourthCollection;

        static ExampleSeven() 
        {
            __anotherCollection = new Dictionary();
        }

        public ExampleSeven() 
        {
            if( __thirdCollection == null )
            {
               __thirdCollection = new Dictionary();
            }
        }

        public static ExampleSeven Create()
        {
           if( __fourthCollection == null ) 
           {
            __fourthCollection = new Dictionary();
           }

           var example = new ExampleSeven();
           return example;
        }

        ...
    }       

例に見られるように、単純なプリミティブではなくクラスオブジェクトであるフィールドにもっと関心があります。宣言されたときにフィールドを初期化すると、クラスがとしてマークされるbeforeinitこと、および宣言されたときに初期化されたフィールドに渡すことができないという事実を理解していthisます。私の懸念は、主に上記の7つの例と同様の場合です。このように混合することで、予期しない問題に備えることができますか?

4

2 に答える 2

2

通常、コンストラクターでフィールドを初期化するか、フィールド初期化子を使用するかは重要ではありません。ただし、操作のタイミングと順序に関して知っておく必要のある微妙な点がいくつかあります。

  • インスタンスフィールドの初期化子とインスタンスコンストラクターは次の順序で実行されますが、これは驚くべきことです。

    • 派生クラスフィールド初期化子
    • 基本クラスフィールド初期化子
    • 基本クラスコンストラクタ
    • 派生クラスコンストラクタ

この動作の理由については、Eric Lippertによるこの記事を参照してください:http://blogs.msdn.com/b/ericlippert/archive/2008/02/18/why-do-initializers-run-in-the-コンストラクターとしての反対の順序-part-two.aspx

  • クラスに静的コンストラクターが存在すると、型の初期化方法に微妙な変化が生じます。ここでは詳細については説明しませんが、Jon Skeetには非常に詳細な記事があります:http://csharpindepth.com/Articles/General/Beforefieldinit.aspx

あなたの質問に答えるために、フィールドを初期化する場所についての明確なルールはありません。初期化が短い場合はフィールドを「インライン」で初期化する方が自然な場合もありますが、長い場合はコンストラクターに含める必要があります。フィールド初期化子にはへの参照を含めることができないため、フィールドをコンストラクターで初期化する必要がある場合がありますthis。私はコードに両方のスタイルが混在していることがよくありますが、これまでのところ、このために問題が発生することはありませんでした。上記の実行順序を覚えておいてください...

于 2013-02-25T16:32:17.120 に答える
0

この質問に対する答えは1つだけではありません。むしろ、それはあなたがフィールドにどんな種類のものを保存したいか、そしてあなたがそれで何をしたいかに依存します。

まず、自問してみてください。このフィールドのオブジェクトは、ExampleXで絶対に必要ですか?ExampleXのすべてのユースケースにそのフィールドが含まれていますか?そうでない場合は、コンストラクターで作成しないでください。1つのメソッドで使用するだけの場合は、そのメソッドで作成する(または渡す)必要があります。さらに2つのメソッドで使用する場合、これらはおそらく独自のクラスにある必要があります。つまり、クラスを2つに分割し、1つはそのフィールドのオブジェクトに依存し、もう1つは依存しません。

次に、ExampleXを作成するたびに、本当に新しい辞書が必要ですか?例を変更してみましょう。辞書の代わりに、ある種のサービス提供オブジェクトであり、セットアップに費用がかかりますが、再利用は簡単です。その場合、作成するのではなく、確実に渡す必要があります。新しいものを作成すると、リソースが無駄になり、非表示の依存関係が導入されるため、プログラムがより複雑で読みにくくなります。オブジェクトを渡すことにより、コンストラクターシグネチャ(またはメソッドに渡す場合はメソッドシグネチャ)で依存関係をアドバタイズします。(単体テストの意味で)テストできない、またはテストが困難になることは言うまでもありません。http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/を参照してください

つまり、要約すると、常に必要ですか?これは、コンストラクターまたは他の場所でオブジェクトを作成/渡すかどうかを示します。そして、それは新しいものでなければなりませんか?それはそれを作成するか、それを渡すかどうかを教えてくれます。

ものを渡すことで、コードの柔軟性も高まります。http://www.kevinwilliampang.com/2009/11/07/dependency-injection-for-dummies/を参照してください

于 2013-02-25T16:52:50.067 に答える