Подтвердить что ты не робот

Инициализация структуры и новый оператор

У меня есть две аналогичные структуры в С#, каждая из которых содержит целое число, но последняя имеет доступ к аксессуарам 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;
    }
}
4b9b3361

Ответ 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;

работает просто отлично.