Domanda

Dando un calcio ad alcune piccole strutture mentre rispondevo a questo post , mi sono imbattuto inaspettatamente nel modo seguente:

La seguente struttura, usando un campo int è perfettamente legale:

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

    public int Size; 
}

Tuttavia, la seguente struttura, utilizzando una proprietà automatica non viene compilata:

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

    public int Size{get; set;}
}

L'errore restituito è " L'oggetto 'this' non può essere usato prima che tutti i suoi campi siano assegnati a " ;. So che questa è una procedura standard per una struttura: il campo di supporto per qualsiasi proprietà deve essere assegnato direttamente (e non tramite il set accessor della proprietà) dall'interno del costruttore della struttura.

Una soluzione consiste nell'utilizzare un campo di supporto esplicito:

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

    private int _size;

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

(Nota che VB.NET non avrebbe questo problema, perché in VB.NET tutti i campi vengono automaticamente inizializzati su 0 / null / false alla prima creazione.)

Ciò sembrerebbe essere una sfortunata limitazione quando si usano le proprietà automatiche con le strutture in C #. Pensando concettualmente, mi chiedevo se questo non sarebbe stato un posto ragionevole in cui ci sarebbe un'eccezione che consente all'accessor del set di proprietà di essere chiamato all'interno del costruttore di una struttura, almeno per una proprietà automatica?

Questo è un problema minore, quasi un caso limite, ma mi chiedevo cosa ne pensassero gli altri su questo ...

È stato utile?

Soluzione

Da C # 6 in poi: questo non è più un problema


Diventato C # 6, è necessario chiamare il costruttore predefinito affinché funzioni:

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

Un problema più grande qui è che hai una struttura mutabile. Questa è mai una buona idea. Lo farei:

public int Size { get; private set; }

Non tecnicamente immutabile, ma abbastanza vicino.

Con le versioni recenti di C #, puoi migliorare su questo:

public int Size { get; }

Questo ora può essere solo nel costruttore.

Altri suggerimenti

Puoi risolverlo chiamando prima il costruttore predefinito:

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

     public int Size { get; set; }
}

Un altro oscuro rimedio a questo problema è quello individuato nella classe temporanea Tuple nella Managed Extensibility Framework (tramite Krzysztof Ko & # 378; 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; }

(Codice sorgente completo da Codeplex: Tuple.cs )

Noto anche che la documentazione per CS0188 è stata aggiornata a aggiungere:

  

Se vedi questo errore quando provi a farlo   inizializzare una proprietà in una struttura   costruttore, la soluzione è cambiare   il parametro del costruttore da specificare   il campo di supporto invece di   proprietà stessa. Auto-implementato   le proprietà dovrebbero essere evitate in   le strutture perché non hanno alcun supporto   campo e quindi non può essere   inizializzato in alcun modo dal   costruttore.

Quindi prendo questo per significare che la guida ufficiale è usare proprietà vecchio stile nelle tue strutture quando ti imbatti in questo problema, che è probabilmente meno oscuro (e più leggibile) di una delle altre due alternative esplorate così più lontano.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top