Автоматические свойства и структуры несовместимы?

StackOverflow https://stackoverflow.com/questions/420433

Вопрос

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

Следующая структура с использованием поля 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;}
}

Возвращается ошибка: «Объект 'this' нельзя использовать, пока не будут назначены все его поля».Я знаю, что это стандартная процедура для структуры:резервное поле для любого свойства должно быть назначено напрямую (а не через метод доступа 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#.Размышляя концептуально, мне было интересно, не было бы разумным местом для исключения, позволяющего вызывать метод доступа к набору свойств внутри конструктора структуры, по крайней мере, для автоматического свойства?

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

Это было полезно?

Решение

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

<Ч>

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

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

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

public int Size { get; private set; }

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

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

public int Size { get; }

Теперь это можно только назначать в конструкторе.

Другие советы

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

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

     public int Size { get; set; }
}

Еще один малоизвестный способ решения этой проблемы найден во временном каталоге. Tuple класс в Платформа управляемой расширяемости (с помощью Кшиштоф Козмич):

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: Кортеж.cs)

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top