无法识别的C#语法

无法识别的C#语法,c#,.net,C#,.net,假设我们有: class Foo { public int IntPropertyInFoo { get; set; } public Bar BarPropertyInA { get; set; } } class Bar { public string StringPropertyInBar { get; set; } } 然后我们想用对象初始值设定项实例化Foo: public static void Main(string[] args) { var

假设我们有:

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

    public Bar BarPropertyInA { get; set; }
}

class Bar
{
    public string StringPropertyInBar { get; set; }
}
然后我们想用对象初始值设定项实例化
Foo

public static void Main(string[] args)
{
    var foo = new Foo
    {
        IntPropertyInFoo = 123,
        BarPropertyInA = // Ommiting new and type name - why does it compile?
        {
            StringPropertyInBar = "something"
        }
    };
}
初始化
BarPropertyInA
的语法让我感到困惑,因为代码编译时没有警告,并且在运行时抛出
NullReferenceException
。我不认识这种语法,但当与字段而不是属性一起使用时,它似乎具有相同的效果

反汇编代码会产生以下结果:

.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
这看起来像:

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

    foo.BarPropertyInA.StringPropertyInBar = "something";
}

如果属性/字段是在构造函数中初始化的,那么这应该是初始化属性/字段成员的一些语法糖吗?

是的,它是初始化以空而不是空开头的属性的一种缩写。net集合属性就是一个很好的例子

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"
};
它还允许您初始化只读属性的值

//compiles and works
var message = new MailMessage { To = { "test@stackoverflow.com" } };

message = new MailMessage
{
    // won't compile: To is read-only
    To = new MailAddressCollection { "test@stackoverflow.com" },
};
从这篇文章中借用了几乎一字不差的内容:

新的less初始值设定项语法允许您使代码更加简洁,并使用初始化语法配置只读属性。事实上,由于大多数基类库和流行的.NET包类都遵循集合属性的空对空模式,因此您几乎总能利用新的less语法。最后,使用newless初始化还意味着您可以保留初始化对象时使用的默认值


这就是为什么我总是在我的类构造函数中新建其他类和列表。如果你有一个
Foo
的构造函数,它将
BarPropertyInA
设置为一个新的
Bar
,那么这就允许你只设置
StringPropertyInBar
属性。他们使用了这个,而不是类似于
BarPropertyInA.StringPropertyInBar=“something”
的东西,我相信数组构造函数和类似的东西也是如此。Net将暗示基于InstanceInit上下文的最佳构造函数似乎答案是肯定的。