Автоматические свойства и структуры не смешиваются? - PullRequest
64 голосов
/ 07 января 2009

Оббирая несколько небольших структур, отвечая на на этот пост , я неожиданно наткнулся на следующее:

Следующая структура, использующая поле int, абсолютно допустима:

struct MyStruct
{ 
    public MyStruct ( int size ) 
    { 
        this.Size = size; // <-- Legal assignment.
    } 

    public int Size; 
}

Однако следующая структура с использованием автоматического свойства не компилируется:

struct MyStruct
{ 
    public MyStruct ( int size ) 
    { 
        this.Size = size; // <-- Compile-Time Error!
    } 

    public int Size{get; set;}
}

Возвращенная ошибка: «Этот объект нельзя использовать, пока все его поля не назначены». Я знаю, что это стандартная процедура для структуры: поле поддержки для любого свойства должно быть назначено напрямую (а не через метод доступа к свойству) из конструктора структуры.

Решением является использование явного поля поддержки:

struct MyStruct
{ 
    public MyStruct(int size)
    {
        _size = size;
    }

    private int _size;

    public int Size
    {
        get { return _size; }
        set { _size = value; }
    }
}

(Обратите внимание, что VB.NET не будет иметь этой проблемы, потому что в VB.NET все поля автоматически инициализируются как 0 / null / false при первом создании.)

Это может показаться неудачным ограничением при использовании автоматических свойств со структурами в C #. Думая концептуально, мне было интересно, не будет ли это разумным местом для исключения, позволяющего вызывать метод доступа к набору свойств в конструкторе структуры, по крайней мере для автоматического свойства?

Это небольшая проблема, почти крайний случай, но мне было интересно, что другие думают об этом ...

Ответы [ 3 ]

83 голосов
/ 07 января 2009

Начиная с C # 6: это больше не проблема


Поскольку C # 6, вам нужно вызвать конструктор по умолчанию, чтобы это работало:

public MyStruct(int size) : this()
{
    Size = size;
}

Большая проблема в том, что у вас есть изменяемая структура. Это никогда хорошая идея. Я бы сделал это:

public int Size { get; private set; }

Не технически неизменный, но достаточно близко.

В последних версиях C # вы можете улучшить это:

public int Size { get; }

Теперь это может быть только в конструкторе.

10 голосов
/ 07 января 2009

Вы можете это исправить, сначала вызвав конструктор по умолчанию:

struct MyStruct 
{
    public MyStruct(int size) : this() 
    {
        this.Size = size; // <-- now works
    }

     public int Size { get; set; }
}
8 голосов
/ 11 февраля 2009

Еще один неясный способ решения этой проблемы - один из обнаруженных во временном классе Tuple в Managed Extensibility Framework (через Krzysztof Koźmic ):

public struct TempTuple<TFirst, TSecond>
{
    public TempTuple(TFirst first, TSecond second)
    {
        this = new TempTuple<TFirst, TSecond>(); // Kung fu!
        this.First = first;
        this.Second = second;
    }

    public TFirst First { get; private set; }
    public TSecond Second { get; private set; }

(Полный исходный код от Codeplex: Tuple.cs )

Также отмечу, что документация для CS0188 была обновлена ​​для добавления:

Если вы видите эту ошибку при попытке инициализировать свойство в структуре конструктор, решение состоит в том, чтобы изменить параметр конструктора для указания вспомогательное поле вместо собственность Авто Реализуемых свойства следует избегать в структуры, потому что они не имеют поддержки поле и, следовательно, не может быть инициализируется каким-либо образом из Конструктор.

Так что я понимаю, что официальное руководство - использовать свойства старого стиля в ваших структурах, когда вы сталкиваетесь с этой проблемой, которая, вероятно, менее неясна (и более читабельна), чем любая из двух других альтернатив, изученных так, далеко.

...