Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unrecognized C# syntax

Tags:

c#

.net

Let's say we have:

class Foo
{
    public int IntPropertyInFoo { get; set; }

    public Bar BarPropertyInA { get; set; }
}

class Bar
{
    public string StringPropertyInBar { get; set; }
}

Then we'd like to instantiate Foo with an object initializer:

public static void Main(string[] args)
{
    var foo = new Foo
    {
        IntPropertyInFoo = 123,
        BarPropertyInA = // Ommiting new and type name - why does it compile?
        {
            StringPropertyInBar = "something"
        }
    };
}

The syntax of initializing BarPropertyInA baffles me, because the code compiles without warnings and, when run, throws NullReferenceException. I don't recognize that syntax, but it seems to have the same effect when used with a field, rather than a property.

Disassembling the compiled code yields this:

.method public hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       34 (0x22)
  .maxstack  3
  .locals init ([0] class Test.Foo foo)
  IL_0000:  nop
  IL_0001:  newobj     instance void Test.Foo::.ctor()
  IL_0006:  dup
  IL_0007:  ldc.i4.s   123
  IL_0009:  callvirt   instance void Test.Foo::set_IntPropertyInFoo(int32)
  IL_000e:  nop
  IL_000f:  dup
  IL_0010:  callvirt   instance class Test.Bar Test.Foo::get_BarPropertyInA()
  IL_0015:  ldstr      "something"
  IL_001a:  callvirt   instance void Test.Bar::set_StringPropertyInBar(string)
  IL_001f:  nop
  IL_0020:  stloc.0
  IL_0021:  ret
} // end of method Program::Main

Which looks like:

public static void Main(string[] args)
{
    var foo = new Foo
    {
        IntPropertyInFoo = 123
    };

    foo.BarPropertyInA.StringPropertyInBar = "something";
}

So is this supposed to be some syntactic sugar for initializing property's/field's members, provided that the property/field is initialized in the constructor?

like image 222
Senior Avatar asked Nov 17 '16 20:11

Senior


Video Answer


1 Answers

Yes, it is a sort of shorthand for initializing properties that start as empty rather than null. The .net collection properties are a good example of this.

var cmd = new System.Data.SqlClient.SqlCommand()
{
    Parameters = 
    {
        new System.Data.SqlClient.SqlParameter() { ParameterName = "@p1", Value = "SomValue"}
    },
    CommandText = "select 1 from Table1 where Value = @p1"
};

It also allows you to initialize the values of read-only properties.

//compiles and works
var message = new MailMessage { To = { "[email protected]" } };

message = new MailMessage
{
    // won't compile: To is read-only
    To = new MailAddressCollection { "[email protected]" },
};

Borrowed pretty much verbatim from this article: http://www.codeducky.org/even-concise-c-object-initializers/

New-less initializer syntax allows you to make your code a bit more concise and to use initialization syntax for configuring read-only properties. Indeed, since most base class library and popular .NET package classes follow the empty over null pattern for collection properties, you can nearly always take advantage of new-less syntax for them. Finally, using new-less initialization also means that you benefit from leaving in place any defaults an object was initialized with.

like image 112
Derpy Avatar answered Oct 03 '22 14:10

Derpy