Nice programing

C #에서 새 개체를 만들 때 {}가 ()처럼 작동합니까?

nicepro 2020. 11. 29. 12:17
반응형

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 #에서 새 개체를 만들 때 {}처럼 작동 합니까 ()?


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 {}

이 중 첫 번째는 가장 일반적인 것입니다.


() -매개 변수없는 생성자를 호출합니다.

{} -속성을 할당하는 데 사용됩니다.

{}without 사용 ()은 바로 가기이며 매개 변수가없는 생성자가있는 한 작동합니다.


개체 이니셜 라이저를 사용하여 형식에 대한 생성자를 명시 적으로 호출하지 않고도 선언적 방식으로 형식 개체를 초기화 할 수 있습니다.

https://msdn.microsoft.com/en-us/library/bb397680.aspx

또한 유형에 기본 생성자가있는 경우 생성자 호출을 생략 할 수 있습니다. 그래서

Customer c1 = new Customer { };

정확히 동일합니다

Customer c1 = new Customer() { };

Customer c1 = new Customer {};

이것은 빈 개체 이니셜 라이저입니다. 당으로 사양 사용하는 생성자를 지정하지 않는 한, 개체 이니셜 라이저는 기본 생성자를 호출합니다. 초기화가 수행되지 않았으므로 기본 생성자를 사용하는 것과 동일하게 컴파일됩니다.

질문에 답하려면 ' 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

As we can see, the first two Customer initializations have been converted into identical IL (IL_0001 to IL_000c). After that, it gets more interesting: From IL_000d to IL_0041, we see that a new object is created and assigned to the invisible temporary variable <>g__initLocal0 and only after that is done, the resulting value is assigned to c3. This is how the object initializer is implemented by the C# compiler. The difference to setting the public properties "manually" after instantiating the object are obvious when you look at how c4 is initialized from IL_0042 to IL_006a - there is no temporary variable.

IL_0070 till the end are equivalent to the previous examples, except they use a non-default constructor in combination with object initializers. As you may expect, it simply gets compiled the same way as before, but with the specified constructor.

Long story short: The outcome, from a C# developer's point of view, is basically the same. Object initializers are simple syntactic sugar and compiler tricks which can help to make code easier to read. However FWIW, the resulting IL is not identical to the manual initialization of the properties. Still, the cost of the invisible temporary variable that's emitted by the compiler should be insignificant in almost all C# programs.


No new version of C# implicitly create a Constructor for object initialization

Customer c1= new Customer{};

Above is same as

Customer c1= new Customer()
{
};

Object and Collection Initializers (C# Programming Guide)


Customer c1= new Customer{} - this is initializer of properties. You can write it as:

Customer c1 = new Customer{
              name="some text",
              ID="some id"
              };

In your specific scenario, yes, it would produce a same result, but not for a reason you probably think.

To understand the result, let's say you have a class like this:

class Customer
{
    public string name;
    public string ID {get; set;}

    public Customer() 
    { 
    }

    public Customer(string n, string id)
    {
        name = n;
        ID = id;
    }
}

When you create it like this:

Customer c = new Customer("john", "someID");

You call the second constructor and tell the class you're passing these values and the responsibility to do what it thinks it's the best lies on the constructor (in this case it would use these values to pass them to public fields).

When you create it like this:

Customer c = new Customer { name = "john", ID = "someID" };

You're setting the public fields by yourself and you use the empty constructor.

Either way, you should AVOID using public fields, because it's not safe. You shouldn't let anyone from outside modify them directly like this. Instead use only private fields and use public properties to manage access from the outside!

참고 URL : https://stackoverflow.com/questions/28254462/does-act-like-when-creating-a-new-object-in-c

반응형