Pergunta

chutando em torno de algumas pequenas estruturas ao responder este post, me deparei com a seguinte inesperadamente:

A estrutura seguinte, usando um campo int é perfeitamente legal:

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

    public int Size; 
}

No entanto, a seguinte estrutura, usando uma propriedade automática não compila:

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

    public int Size{get; set;}
}

O erro é "O 'isto' objeto não pode ser usado antes de todos os seus campos são atribuídos a". Eu sei que este é um procedimento padrão para uma struct: o campo de apoio para qualquer propriedade deve ser atribuído directamente (e não através do conjunto acessor da propriedade) de dentro o construtor do struct.

A solução é usar um campo de apoio explícito:

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

    private int _size;

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

(Note que VB.NET não tem esse problema, porque em VB.NET todos os campos são automaticamente inicializados com 0 / null / false quando criada pela primeira vez.)

Esta parece ser uma limitação infeliz ao usar propriedades automáticas com estruturas em C #. Pensando conceitualmente, eu queria saber se isso não seria um lugar razoável para que haja uma exceção que permite o acessor conjunto de propriedades a ser chamado no construtor de um struct, pelo menos para uma propriedade automática?

Esta é uma questão menor, quase um caso limite, mas eu queria saber o que os outros pensavam sobre isso ...

Foi útil?

Solução

De C # 6 em diante: isso não é mais um problema


Becore C # 6, você precisa chamar o construtor padrão para que isso funcione:

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

Um problema maior aqui é que você tem um struct mutável. Esta é não uma boa idéia. Gostaria de fazê-lo:

public int Size { get; private set; }

Não tecnicamente imutável, mas perto o suficiente.

Com as versões recentes do C #, você pode melhorar este:

public int Size { get; }

Isto pode agora única ser atribuído no construtor.

Outras dicas

Você pode corrigir isso, primeiro chamando o construtor padrão:

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

     public int Size { get; set; }
}

Outra forma de contornar obscura para este problema é um visto na classe Tuple temporária no Managed Extensibility Framework (via Krzysztof Kozmic ):

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; }

(código-fonte completo do CodePlex: Tuple.cs )

Eu também notar que a documentação do CS0188 foi atualizado para adicionar:

Se você ver este erro ao tentar inicializar uma propriedade em um struct construtor, a solução é a mudança o parâmetro de construtor para especificar o campo de suporte em vez da própria propriedade. Auto-implementado propriedades devem ser evitadas em structs, porque eles não têm qualquer apoio campo e, portanto, não pode ser inicializado de alguma forma a partir da construtor.

Então, eu que isso significa que a orientação oficial é usar propriedades de estilo antigo em suas estruturas quando você correr para este problema, que é provavelmente menos obscuro (e mais readible) do que qualquer das outras duas alternativas exploradas de modo longe.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top