Инициализация структуры и новый оператор
У меня есть две аналогичные структуры в С#, каждая из которых содержит целое число, но последняя имеет доступ к аксессуарам get/set.
Почему мне нужно инициализировать структуру Y
с помощью оператора new
до назначения поля a
? Является ли Y
типом значения, когда я инициализирую его с помощью new
?
public struct X
{
public int a;
}
public struct Y
{
public int a { get; set; }
}
class Program
{
static void Main(string[] args)
{
X x;
x.a = 1;
Y y;
y.a = 2; // << compile error "unused local variable" here
Y y2 = new Y();
y2.a = 3;
}
}
Ответы
Ответ 1
Причина, по которой одна из них действительна, а другая - нет, заключается в том, что вы не можете вызывать методы для неинициализированных объектов. Средства для создания объектов также являются методами.
public struct X
{
public int a;
public void setA(int value)
{ this.a = value; }
}
public struct Y
{
public int a { get; set; }
}
class Program
{
static void Main(string[] args)
{
X x;
x.setA(1); // A: error
x.a = 2; // B: okay
Y y;
y.a = 3; // C: equivalent to A
}
}
Причина, по которой не допускается, заключается в том, что средство установки свойств могло наблюдать неинициализированное состояние объекта. Вызывающий не знает, просто ли установил свойство set, или делает больше.
Ответ 2
В первом случае вы просто назначаете поле. Это не связано с фактическим использованием структуры, просто устанавливая значение в память (адрес структуры + смещение поля в стеке).
Во втором случае вы вызываете метод set_a(int value)
, но сбой, потому что переменная не инициализирована.
В третьем случае конструктор инициализирует его для вас, поэтому использование переменной в порядке.
Обновление: здесь идет спецификация!
"12.3 Определенное назначение" (стр. 122 из ecma-334).
Переменная struct-type считается определенно назначенной, если каждая из ее переменных экземпляра считается определенно назначенной
Ответ 3
Это описано в разделе С# спецификации, посвященном "Определенное присвоение" :
переменная struct-type считается определенно назначенной, если каждая из ее переменных экземпляра считается определенно назначенной.
и
Первоначально неназначенная переменная (раздел 5.3.2) считается определенно назначенной в данном месте, если все возможные пути выполнения, ведущие к этому местоположению, содержат по меньшей мере одно из следующего:
* Простое назначение (раздел 7.13.1), в котором переменная является левым операндом.
*...
Таким образом, это также работает:
void Main()
{
X x;
x.a = 1;
x.b = 2;
x.Dump();
}
public struct X
{
public int a;
public int b;
}
Вы можете проверить это в LINQPad.
Обратите внимание, что компилятор не может доказать, что переменная struct-type считается определенно назначенной, если вы вызываете код на ней и что вы делаете с свойством. Таким образом, прежде чем вы сможете использовать свойство в переменной типа struct, оно должно быть обязательно назначено.
Ответ 4
Оператор new
для типов значений запускает указанный конструктор. В отличие от ссылочных типов, это необязательно, поэтому, если вы не используете new
, конструктор по умолчанию неявно запускается (вы не можете указать свой собственный конструктор по умолчанию, поэтому он всегда дает значение по умолчанию для полей для их типы).
Что касается ошибки компилятора, я не уверен. Интересно, что в интерактивном окне С#
public struct Y
{
public int a { get; set; }
}
Y test;
test.a = 5;
работает просто отлично.