違いはありますか?
class example
{
int i = 5;
}
class example2
{
int i;
public example2()
{
i = 5;
}
}
変数を宣言した後に値を与えるのは好きではないので、私は 2 番目の方法を好みます。しかし、技術的に違いはありますか?
はい。誰かがあなたのクラスから派生しexample2
、基本クラスのコンストラクターを呼び出すのを忘れた場合、初期化がスキップされてしまう可能性があります。
コンストラクターのパラメーターに依存しない場合、(最初の例のように) 宣言の時点での初期化を好む傾向があります。
簡単な答え :いいえ
長い答え:
生成された を見ると、クラスの初期化が行わIL code
れる場合example
、コンストラクターを呼び出す前に、クラスのようにexample2
クラスの初期化がコンストラクター内で行われます。
example
クラス
.class private auto ansi beforefieldinit example
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldc.i4.5
L_0002: stfld int32 ConsoleApplication1.example::i
L_0007: ldarg.0
L_0008: call instance void [mscorlib]System.Object::.ctor()
L_000d: ret
}
.field private int32 i
}
そしてexample2
クラスのために
.class private auto ansi beforefieldinit example2
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: call instance void [mscorlib]System.Object::.ctor()
L_0006: ldarg.0
L_0007: ldc.i4.5
L_0008: stfld int32 ConsoleApplication1.example2::i
L_000d: ret
}
.field private int32 i
}
違いがある状況が発生する可能性があると言わざるを得ません(ただし、コードが質問に投稿されたものと同じくらい単純であれば、もちろん違いはありません)。
次のコードを検討してください。
public class Class1
{
public Class1()
{
Foo();
}
public virtual void Foo()
{
}
}
public class Class2 : Class1
{
protected int i = 5;
protected int j;
public Class2()
{
j = 5;
}
public override void Foo()
{
Console.WriteLine("i:" + i);
Console.WriteLine("j:" + j);
}
}
そしてそれをテストする
new Class2().Foo();
出力は次のようになります。
i:5
j:0
i:5
j:5
手がかりは、初期化子 (フィールド宣言で値を割り当てるとき) が基本クラスのコンストラクターの前に実行されることです。そのため、コンストラクターFoo
から呼び出されたときは、デフォルト値、つまり. しかし、完全に作成された変数を呼び出したとき (コンストラクターが完了したとき) には、既に value があります。Class1
j
0
Foo
new Class2().Foo();
Class2
j
5
基本クラスのコンストラクターでメソッドを呼び出すのは危険な設計ですが、virtual
禁止されているわけではなく、注意が必要です。
以下は、C# による J.Richter CLR からの抜粋です。
コンパイラは、基本クラスのコンストラクターを呼び出す前に、便利な構文を使用してフィールドを初期化し、これらのフィールドが常にソース コードの外観が指示する値を持っているという印象を維持します。潜在的な問題は、基本クラスのコンストラクターが、派生クラスによって定義されたメソッドにコールバックする仮想メソッドを呼び出すときに発生します。これが発生した場合、便利な構文を使用して初期化されたフィールドは、仮想メソッドが呼び出される前に初期化されています。