最初に設定されるクラス宣言は、コンストラクターで設定するのと内部的に同じですか?
例:
class test
{
int test1 = 5;
}
それとの間に違いはありますか
class test
{
int test1;
public test()
{
test1 = 5;
}
}
違いがない場合、どちらを行うのが正しいですか?
最初に設定されるクラス宣言は、コンストラクターで設定するのと内部的に同じですか?
例:
class test
{
int test1 = 5;
}
それとの間に違いはありますか
class test
{
int test1;
public test()
{
test1 = 5;
}
}
違いがない場合、どちらを行うのが正しいですか?
特定のケースでは、機能的な違いはありません。ただし、継承が含まれる場合、フィールド初期化子は驚くべき方法で動作する可能性があります。フィールド初期化子は実際にはコンストラクターの前に呼び出され、コンストラクターは最小派生から最大派生に呼び出されますが、フィールド初期化子は最大派生から最小派生に呼び出されます。したがって、クラスAがBから派生している場合、Aのインスタンスが作成されると、次のシーケンスが実行されます。Aのフィールド初期化子、Bのフィールド初期化子、System.Objectコンストラクター、Bのコンストラクター、Aのコンストラクター。
上記は、インスタンスフィールドの初期化子/コンストラクターにのみ適用されます。静的フィールド初期化子/コンストラクターの場合、動作は完全に異なります。
あなたの場合、どちらが正しいかについては、合意された慣習はありませんが、一貫性は通常、読者に高く評価されています。
ほとんどの場合、メンバー初期化の2つのスタイルは機能的に同等であると見なすことができます。
ただし、メンバー宣言で行われた割り当ては、コンストラクターが実行される前に実行されることに注意してください。Jon Skeetがコメントで指摘しているように、仮想メソッドがベースコンストラクターから呼び出された場合、このタイミングの違いによって観察可能なアーティファクトが作成される可能性があります。
「正しさ」は意見の問題です。単純な整数値の場合、初期値の割り当ては十分に無害に見えますが、日付やその他の完全なオブジェクトなどのより複雑なタイプに入ると、クラッター係数が上昇し始めます。
私自身は、一般的に、初期化がコンストラクターの本体で明示的な代入ステートメントとして実行され、宣言でクラス全体に散らばっていないことを望んでいます。
ILコードの違いを見ると、ケース1ではコンストラクターが呼び出される前に変数テストが割り当てられ、ケース2ではコンストラクターが呼び出された後に変数テストが割り当てられていることがわかります。
ケース1
.class public auto ansi beforefieldinit WebApplication1.Class1
extends [mscorlib]System.Object
{
// Fields
.field public int32 test1
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x28d3
// Code size 15 (0xf)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.5
IL_0002: stfld int32 WebApplication1.Class1::test1 <- HERE
IL_0007: ldarg.0
IL_0008: call instance void [mscorlib]System.Object::.ctor() <- HERE
IL_000d: nop
IL_000e: ret
} // end of method Class1::.ctor
} // end of class WebApplication1.Class1
ケース2
.class public auto ansi beforefieldinit WebApplication1.Class2
extends [mscorlib]System.Object
{
// Fields
.field public int32 test1
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x28e3
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor() <- HERE
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0
IL_0009: ldc.i4.5
IL_000a: stfld int32 WebApplication1.Class2::test1 <- HERE
IL_000f: nop
IL_0010: ret
} // end of method Class2::.ctor
} // end of class WebApplication1.Class2
あなたの場合、それは同じことです。しかし、パラメーター化されたコンストラクターがあり、test1がコンストラクターから渡された値から割り当てられた場合はどうなりますか。
class test
{
int test1;
public test()
{
test1 = 5;
}
public test(int ctest)
{
test1 = ctest;
}
}
If there is no difference, which is more correct to do?
必要なものを選択するのは開発者次第です。
これはインスタンスフィールドの初期化と呼ばれます:
class Test
{
int test1 = 5;
}
それはどのように機能しますか?
クラスのインスタンスフィールド変数初期化子は、そのクラスのインスタンスコンストラクター(セクション10.10.1)のいずれかに入るとすぐに実行される一連の割り当てに対応します。変数初期化子は、クラス宣言に表示されるテキスト順に実行されます。
したがって、あなたの場合、フィールド初期化のこれら2つのバリアントは機能的に同じです。
また、この質問を確認することをお勧めします。C#メンバー変数の初期化。ベストプラクティス?。