Действует ли {} как () при создании нового объекта в C#?
Я только что заметил, что с помощью {} вместо () дает те же результаты при строительстве объекта.
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#?
7 ответов:
существует три способа непосредственного создания нового объекта в C#:
простой вызов конструктора со списком аргументов:
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" }последняя форма является в точности эквивалентно для указания пустого списка аргументов. Обычно это называем конструктор без параметров, но это может вызов конструктора, где все параметры имеют значения по умолчанию.
теперь в обоих примерах инициализатора объекта, которые я дал, я установил
Nameсвойство-и вы можете установить другие свойства / поля, или даже установить нет свойства и поля. Таким образом, все три из них эквивалентны, эффективно не передавая аргументы конструктора и не указывая никаких свойств/полей для установки:new Foo() new Foo() {} new Foo {}из них первый-самый обычный.
()- вызывает конструктор без параметров.
{}- предполагается использовать для присвоения свойств.используя
{}без()ярлык и будет работать пока есть конструктор без параметров.
инициализаторы объектов можно использовать для декларативной инициализации объектов типа без явного вызова конструктора для типа.
https://msdn.microsoft.com/en-us/library/bb397680.aspx
также вы можете опустить вызов конструктора, если тип имеет contructor по умолчанию. Так что
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как видим, первые два
Customerинициализации были преобразованы в идентичный IL (IL_0001 в IL_000c). После этого становится еще интереснее: от IL_000d до IL_0041 мы видим, что создается новый объект и присваивается невидимой временной переменной<>g__initLocal0и только после это делается, результирующее значение присваиваетсяc3. Вот как инициализатор объекта реализуется компилятором C#. Разница в настройке общедоступных свойств "вручную" после создания экземпляра объекта очевидна, когда вы смотрите на howc4инициализируется от IL_0042 до IL_006a-нет временной переменной.IL_0070 до конца эквивалентны предыдущим примерам, за исключением того, что они используют конструктор не по умолчанию в сочетании с инициализаторами объектов. Как и следовало ожидать, он просто компилируется так же, как и раньше, но с указанным конструктором.
короче говоря: результат, с точки зрения разработчика C#, в основном тот же. Инициализаторы объектов-это простые синтаксические сахара и компиляторные трюки, которые могут помочь облегчить чтение кода. Однако чистки рядов, в результате чего ил не идентична ручной инициализации свойства. Тем не менее, стоимость невидимой временной переменной, которая испускается компилятор должен быть незначительным почти во всех программах на C#.
нет новой версии C# неявно создать конструктор для инициализации объекта
Customer c1= new Customer{};выше это же как
Customer c1= new Customer() { };инициализаторы объектов и коллекций (руководство по программированию в C#)
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");вы вызываете второй конструктор и говорите классу, что вы передаете эти значения, и ответственность за то, что он считает лучшим, лежит на конструкторе (в этом случае он будет использовать эти значения для их передачи открытые поля.)
когда вы создаете его так:
Customer c = new Customer { name = "john", ID = "someID" };вы устанавливаете общедоступные поля самостоятельно и используете пустой конструктор.
В любом случае, вы должны избегать использования открытых полей, потому что это не безопасно. Вы не должны позволять никому извне изменять их прямо так. Вместо этого используйте только частные поля и используйте общедоступные свойства для управления доступом извне!
Comments