3

重複の可能性:
C# メンバー変数の初期化。ベストプラクティス?
コンストラクターでメンバー変数を初期化する必要があるのはなぜですか?
コンストラクター内またはコンストラクター外で変数を初期化する必要があります

Java/C# では通常、

public class MyClass {
    private MyObject myObject;

    public MyClass(){
        myObject = new MyObject();
    }
}

それ以外の

public class MyClass {
    private MyObject myObject = new MyObject();

    public MyClass(){

    }
}

あるとすればその理由は何ですか?

4

2 に答える 2

1

違いはありません。スタイルの選択です。

あなたの例では、2 番目のアプローチを選択すると、コンストラクターを提供する必要がないため、数行のコードを節約できます。

于 2012-08-28T17:34:41.410 に答える
1

これは、コメントの1つで述べられているように、コーディングの好みに要約されます。次のコードをコンパイルすると

public class TestInitialization
{
    private object test1 = new object();
    private object test2;

    public TestInitialization()
    {
        this.test2 = new object();
    }
}

コンパイルすると、実際に使用されるコードは次のようになります。

public class TestInitialization
{
    private object test1;
    private object test2;

    public TestInitialization()
    {
        this.test1 = new object();
        this.test2 = new object();
    }
}

全く同じものなので、好きな方を使ってください。

編集: これは、継承されたクラスと結果としてコンパイルされた IL を持つ基本クラスの例です。

基本クラス

class basetest
{
    private object test1 = new object();
    private object test2;

    public basetest()
    {
        this.test2 = new object();
    }
}

継承されたクラス

class testclass : basetest
{
    private object testclass1 = new object();
    private object testclass2;

    public testclass() : base()
    {
        this.testclass2 = new object();
    }
}

結果の IL 基本クラス

.class private auto ansi beforefieldinit basetest
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: newobj instance void [mscorlib]System.Object::.ctor()
        L_0006: stfld object logtest.basetest::test1
        L_000b: ldarg.0 
        L_000c: call instance void [mscorlib]System.Object::.ctor()
        L_0011: nop 
        L_0012: nop 
        L_0013: ldarg.0 
        L_0014: newobj instance void [mscorlib]System.Object::.ctor()
        L_0019: stfld object logtest.basetest::test2
        L_001e: nop 
        L_001f: ret 
    }


    .field private object test1

    .field private object test2

}

継承クラス IL

.class private auto ansi beforefieldinit testclass
    extends logtest.basetest
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: newobj instance void [mscorlib]System.Object::.ctor()
        L_0006: stfld object logtest.testclass::testclass1
        L_000b: ldarg.0 
        L_000c: call instance void logtest.basetest::.ctor()
        L_0011: nop 
        L_0012: nop 
        L_0013: ldarg.0 
        L_0014: newobj instance void [mscorlib]System.Object::.ctor()
        L_0019: stfld object logtest.testclass::testclass2
        L_001e: nop 
        L_001f: ret 
    }


    .field private object testclass1

    .field private object testclass2

}

私の側に少し混乱があると思います。この例では、コンストラクターの外側のイニシャライザーは、基本コンストラクターが呼び出される直前に FIRST で初期化されます。したがって、コンストラクターの外側の初期化子は、コンストラクター内の初期化子の前に最初に初期化されますが、ほとんどの場合、これは問題になりません。技術的には、それらはすべてコンストラクター内で初期化されるように変換され、次の規則が適用されます。

  1. コンストラクタの外側にあるすべてのイニシャライザが最初に実行されます
  2. すべての基本クラスのコンストラクターが呼び出されます
  3. コンストラクター内のすべての初期化子が実行されます

基本的に、コンパイラはコンストラクタの外側にあるすべてのイニシャライザをコンストラクタ コードの先頭に追加し、通常どおり実行します。

したがって、この

public class test : basetest
{
    private object test1 = new object();
    private object test2;

    public test() : base()
    {
        this.test2 = new object();
    }
}

public class basetest
{
    private object basetest1 = new object();
    private object basetest2;

    public basetest()
    {
        this.basetest2 = new object();
    }
}

になる

public class test : basetest
{
    private object test1;
    private object test2;

    public test()
    {
        //prepend everything first
        this.test1 = new object();

        //call base
        base(); //not legal but just an example

        //everything else that was already here
        this.test2 = new object();
    }
}

public class basetest
{
    private object basetest1;
    private object basetest2;

    public basetest()
    {
        //prepend initializers
        this.basetest1 = new object();

        //if there were more base classes, the constructors would be called here

        //do everything else that was already here
        this.basetest2 = new object();
    }
}

うまくいけば、それはより理にかなっていて、いくつかの問題を解決します。コンストラクターの「最初」または「外側」で実行されると言ったときに何人かの人々が何を意味しているのかを理解するのに問題があったことは知っています。実際にはコンストラクター内ですべて実行されますが、呼び出される順序は影響を受けます。

于 2012-08-28T17:36:59.803 に答える