Непризнанный синтаксис С#
Скажем, мы имеем:
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";
}
Итак, это должен быть какой-то синтаксический сахар для инициализации членов свойства/поля при условии, что свойство /field инициализируется в конструкторе?
Ответы
Ответ 1
Да, это своего рода сокращение для инициализации свойств, которые начинаются как пустые, а не нулевые. Хорошим примером этого являются свойства коллекции .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 = { "[email protected]" } };
message = new MailMessage
{
// won't compile: To is read-only
To = new MailAddressCollection { "[email protected]" },
};
Заимствовано довольно много дословно из этой статьи:
http://www.codeducky.org/even-concise-c-object-initializers/
Новый синтаксис инициализатора позволяет сделать код более кратким и использовать синтаксис инициализации для настройки свойств только для чтения. Действительно, поскольку большинство базовых классов и популярных классов пакетов .NET следуют за пустым более чем null шаблоном для свойств коллекции, вы почти всегда можете использовать синтаксис без изменений. Наконец, использование инициализации без инициализации также означает, что вам выгодно оставлять на месте любые значения по умолчанию, с которыми был инициализирован объект.