Does { } act like ( ) when creating a new object in C#?

C#.NetInstantiation

C# Problem Overview


I just noticed that using {} instead of () gives the same results when constructing an object.

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"};
}

Does {} act like () when creating a new object in C#?

C# Solutions


Solution 1 - C#

There are three ways of directly creating a new object in C#:

  • A simple constructor call with an argument list:

      new Foo()       // Empty argument list
      new Foo(10, 20) // Passing arguments
    
  • An object initializer with an argument list

      new Foo() { Name = "x" }       // Empty argument list
      new Foo(10, 20) { Name = "x" } // Two arguments
    
  • An object initializer with no argument list

      new Foo { Name = "x" }
    

The last form is exactly equivalent to specifying an empty argument list. Usually it will call a parameterless constructor, but it could call a constructor where all the parameters have default values.

Now in both the object initializer examples I've given, I've set a Name property - and you could set other properties/fields, or even set no properties and fields. So all three of these are equivalent, effectively passing no constructor arguments and specifying no properties/fields to set:

new Foo()
new Foo() {}
new Foo {}

Of these, the first is the most conventional.

Solution 2 - C#

() - calls the parameterless constructor.

{} - is supposed to be used to assign properties.

Using {} without () is a shortcut and will work as long as there is a parameterless constructor.

Solution 3 - C#

>You can use object initializers to initialize type objects in a declarative manner without explicitly invoking a constructor for the type.

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

Also you can omit calling the constructor if the type has default contructor. So

Customer c1 = new Customer { };

is exactly the same as

Customer c1 = new Customer() { };

Solution 4 - C#

Customer c1 = new Customer {};

This is an empty object initializer. As per the [spec][1], object initializers will call the default constructor unless you specify the constructor to use. Since no initialization is done, it will be compiled the same as using the default constructor.

To answer the question, if ‘{} act[s] like () when creating a new object in C#’, we have to go into more detail. For all you care about, the resulting objects will contain the same data, but the generated IL is not identical.

The following example

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";
        }
    }
}

will compile to this IL (main method only, Debug without optimizations)

.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.

[1]: https://msdn.microsoft.com/library/ms228593.aspx "C# Language Specification, 7.6.10.2 Object initializers"

Solution 5 - C#

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)

Solution 6 - C#

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

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

Solution 7 - C#

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!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser4451265View Question on Stackoverflow
Solution 1 - C#Jon SkeetView Answer on Stackoverflow
Solution 2 - C#Nadia ChibrikovaView Answer on Stackoverflow
Solution 3 - C#Nikolay KostovView Answer on Stackoverflow
Solution 4 - C#hangyView Answer on Stackoverflow
Solution 5 - C#Midhun MundayadanView Answer on Stackoverflow
Solution 6 - C#vladb9582View Answer on Stackoverflow
Solution 7 - C#waltherView Answer on Stackoverflow