Действует ли {} как () при создании нового объекта в 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#?

586   7  

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#. Разница в настройке общедоступных свойств "вручную" после создания экземпляра объекта очевидна, когда вы смотрите на how c4 инициализируется от 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

    Ничего не найдено.