A structure is declared using struct keyword. The default modifier is internal for the struct and its members. The following example declares a structure Coordinate for the graph. A struct object can be created with or without the new operator, same as primitive type variables.
csharp. 3) Creating an Array of objects: If you need the multiple numbers of objects of the same class you can create an array of objects. This will require you to declare the array first and then initialize each element { object in this case }.
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.
()
- 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.
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() { };
Customer c1 = new Customer {};
This is an empty object initializer. As per the spec, 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With