{}
の代わりに ()
は、オブジェクトの構築時に同じ結果をもたらします。
class Customer
{
public string name;
public string ID {get; set;}
}
static void Main()
{
Customer c1= new Customer{}; //Is this a constructor?
Customer c2= new Customer();
//what is the concept behind the ability to assign values for properties
//and fields inside the {} and is not allowable to do it inside ()
//without defining a constructor:
Customer c3= new Customer{name= "John", ID="ABC"};
}
します{}
のように振る舞う ()
C#で新しいオブジェクトを作成するとき?
C#で新しいオブジェクトを直接作成するには、3つの方法があります。
引数リストを使用した単純なコンストラクター呼び出し:
new Foo() // Empty argument list
new Foo(10, 20) // Passing arguments
引数リストを持つオブジェクト初期化子
new Foo() { Name = "x" } // Empty argument list
new Foo(10, 20) { Name = "x" } // Two arguments
引数リストのないオブジェクト初期化子
new Foo { Name = "x" }
最後の形式は完全に等価で、空の引数リストを指定します。通常はパラメーターなしのコンストラクターを呼び出しますが、couldはすべてのパラメーターがデフォルト値を持つコンストラクターを呼び出します。
ここで示した両方のオブジェクト初期化子の例で、Name
プロパティを設定しました。他のプロパティ/フィールドを設定したり、noプロパティやフィールドを設定したりすることもできます。したがって、これら3つはすべて同等であり、コンストラクタ引数を効果的に渡さず、設定するプロパティ/フィールドを指定しません。
new Foo()
new Foo() {}
new Foo {}
これらのうち、最初のものが最も一般的です。
()
-パラメーターなしのコンストラクターを呼び出します。
{}
-プロパティの割り当てに使用されることになっています。
{}
なしで()
を使用することはショートカットであり、パラメーターのないコンストラクターがある限り機能します。
オブジェクト初期化子を使用すると、型のコンストラクターを明示的に呼び出すことなく、宣言的な方法で型オブジェクトを初期化できます。
https://msdn.Microsoft.com/en-us/library/bb397680.aspx
また、型にデフォルトのコンストラクタがある場合は、コンストラクタの呼び出しを省略できます。そう
Customer c1 = new Customer { };
とまったく同じです
Customer c1 = new Customer() { };
Customer c1 = new Customer {};
これは空のオブジェクト初期化子です。 spec のとおり、使用するコンストラクターを指定しない限り、オブジェクト初期化子はデフォルトのコンストラクターを呼び出します。初期化は行われないため、デフォルトのコンストラクタを使用する場合と同じようにコンパイルされます。
質問に答えるために、「{}
が、C#で新しいオブジェクトを作成するときに()
のように動作する」場合は、さらに詳しく説明する必要があります。気になることはすべて、結果のオブジェクトには同じデータが含まれますが、生成されたILは同一ではありません。
次の例
namespace SO28254462
{
class Program
{
class Customer
{
private readonly Foo foo = new Foo();
public string name;
public Customer()
{
}
public Customer(string id)
{
this.ID = id;
}
public string ID { get; set; }
public Foo Foo
{
get
{
return this.foo;
}
}
}
class Foo
{
public string Bar { get; set; }
}
static void Main(string[] args)
{
Customer c1 = new Customer { };
Customer c2 = new Customer();
Customer c3 = new Customer { name = "John", ID = "ABC", Foo = { Bar = "whatever" } };
Customer c4 = new Customer();
c4.name = "John";
c4.ID = "ABC";
c4.Foo.Bar = "whatever";
Customer c5 = new Customer("ABC") { name = "John", Foo = { Bar = "whatever" } };
Customer c6 = new Customer("ABC");
c6.name = "John";
c6.Foo.Bar = "whatever";
}
}
}
このILにコンパイルされます(メインメソッドのみ、最適化なしのデバッグ)
.method private hidebysig static
void Main (
string[] args
) cil managed
{
// Method begins at RVA 0x2050
// Code size 201 (0xc9)
.maxstack 2
.entrypoint
.locals init (
[0] class SO28254462.Program/Customer c1,
[1] class SO28254462.Program/Customer c2,
[2] class SO28254462.Program/Customer c3,
[3] class SO28254462.Program/Customer c4,
[4] class SO28254462.Program/Customer c5,
[5] class SO28254462.Program/Customer c6,
[6] class SO28254462.Program/Customer '<>g__initLocal0',
[7] class SO28254462.Program/Customer '<>g__initLocal1'
)
IL_0000: nop
IL_0001: newobj instance void SO28254462.Program/Customer::.ctor()
IL_0006: stloc.0
IL_0007: newobj instance void SO28254462.Program/Customer::.ctor()
IL_000c: stloc.1
IL_000d: newobj instance void SO28254462.Program/Customer::.ctor()
IL_0012: stloc.s '<>g__initLocal0'
IL_0014: ldloc.s '<>g__initLocal0'
IL_0016: ldstr "John"
IL_001b: stfld string SO28254462.Program/Customer::name
IL_0020: ldloc.s '<>g__initLocal0'
IL_0022: ldstr "ABC"
IL_0027: callvirt instance void SO28254462.Program/Customer::set_ID(string)
IL_002c: nop
IL_002d: ldloc.s '<>g__initLocal0'
IL_002f: callvirt instance class SO28254462.Program/Foo SO28254462.Program/Customer::get_Foo()
IL_0034: ldstr "whatever"
IL_0039: callvirt instance void SO28254462.Program/Foo::set_Bar(string)
IL_003e: nop
IL_003f: ldloc.s '<>g__initLocal0'
IL_0041: stloc.2
IL_0042: newobj instance void SO28254462.Program/Customer::.ctor()
IL_0047: stloc.3
IL_0048: ldloc.3
IL_0049: ldstr "John"
IL_004e: stfld string SO28254462.Program/Customer::name
IL_0053: ldloc.3
IL_0054: ldstr "ABC"
IL_0059: callvirt instance void SO28254462.Program/Customer::set_ID(string)
IL_005e: nop
IL_005f: ldloc.3
IL_0060: callvirt instance class SO28254462.Program/Foo SO28254462.Program/Customer::get_Foo()
IL_0065: ldstr "whatever"
IL_006a: callvirt instance void SO28254462.Program/Foo::set_Bar(string)
IL_006f: nop
IL_0070: ldstr "ABC"
IL_0075: newobj instance void SO28254462.Program/Customer::.ctor(string)
IL_007a: stloc.s '<>g__initLocal1'
IL_007c: ldloc.s '<>g__initLocal1'
IL_007e: ldstr "John"
IL_0083: stfld string SO28254462.Program/Customer::name
IL_0088: ldloc.s '<>g__initLocal1'
IL_008a: callvirt instance class SO28254462.Program/Foo SO28254462.Program/Customer::get_Foo()
IL_008f: ldstr "whatever"
IL_0094: callvirt instance void SO28254462.Program/Foo::set_Bar(string)
IL_0099: nop
IL_009a: ldloc.s '<>g__initLocal1'
IL_009c: stloc.s c5
IL_009e: ldstr "ABC"
IL_00a3: newobj instance void SO28254462.Program/Customer::.ctor(string)
IL_00a8: stloc.s c6
IL_00aa: ldloc.s c6
IL_00ac: ldstr "John"
IL_00b1: stfld string SO28254462.Program/Customer::name
IL_00b6: ldloc.s c6
IL_00b8: callvirt instance class SO28254462.Program/Foo SO28254462.Program/Customer::get_Foo()
IL_00bd: ldstr "whatever"
IL_00c2: callvirt instance void SO28254462.Program/Foo::set_Bar(string)
IL_00c7: nop
IL_00c8: ret
} // end of method Program::Main
ご覧のとおり、最初の2つのCustomer
初期化は同一のIL(IL_0001からIL_000c)に変換されています。その後、さらに興味深いものになります。IL_000dからIL_0041まで、新しいオブジェクトが作成され、非表示の一時変数<>g__initLocal0
に割り当てられ、その後、結果の値がc3
に割り当てられます。これは、C#コンパイラによってオブジェクト初期化子が実装される方法です。 c4
がIL_0042からIL_006aに初期化される方法を見ると、オブジェクトをインスタンス化した後で「手動で」パブリックプロパティを設定することとの違いは明らかです-一時的な変数はありません。
最後までIL_0070は、デフォルト以外のコンストラクターをオブジェクト初期化子と組み合わせて使用することを除いて、前の例と同等です。ご想像のとおり、これは前と同じ方法でコンパイルされますが、指定されたコンストラクターを使用します。
要するに、C#開発者の観点から見た結果は基本的に同じです。オブジェクト初期化子は、コードを読みやすくするのに役立つ単純な構文シュガーおよびコンパイラトリックです。ただし、FWIWでは、結果のILは、プロパティの手動初期化と同じではありません。それでも、コンパイラーによって発行される非表示の一時変数のコストは、ほとんどすべてのC#プログラムで重要ではありません。
C#の新しいバージョンでは、オブジェクトの初期化のためのコンストラクタを暗黙的に作成しません
Customer c1= new Customer{};
上記は同じです
Customer c1= new Customer()
{
};
Customer c1= new Customer{}
-これはプロパティの初期化子です。あなたはそれを次のように書くことができます:
Customer c1 = new Customer{
name="some text",
ID="some id"
};
特定のシナリオでは、はい、同じ結果が得られますが、おそらくあなたが考える理由ではありません。
結果を理解するために、次のようなクラスがあるとします。
class Customer
{
public string name;
public string ID {get; set;}
public Customer()
{
}
public Customer(string n, string id)
{
name = n;
ID = id;
}
}
次のように作成すると、
Customer c = new Customer("john", "someID");
2番目のコンストラクターを呼び出して、クラスにこれらの値を渡すことと、コンストラクターに最適と思われることを実行する責任を伝えます(この場合、これらの値を使用してパブリックフィールドに渡します)。
次のように作成すると、
Customer c = new Customer { name = "john", ID = "someID" };
あなたは自分でパブリックフィールドを設定していて、空のコンストラクタを使用しています。
どちらの方法でも、安全ではないため、パブリックフィールドを使用しないでください。外部からだれもがこのように直接変更できないようにする必要があります。代わりに、プライベートフィールドのみを使用し、パブリックプロパティを使用して外部からのアクセスを管理します。