Por que é necessário chamar: esta () em um struct usar propriedades automáticas no c #?

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

Pergunta

Se eu definir uma struct em C # usando propriedades automáticas como esta:

public struct Address
{
    public Address(string line1, string line2, string city, string state, string zip)
    {
        Line1 = line1;
        Line2 = line2;
        City = city;
        State = state;
        Zip = zip;
    }

    public string Line1 { get; protected set; }
    public string Line2 { get; protected set; }
    public string City { get; protected set; }
    public string State { get; protected set; }
    public string Zip { get; protected set; }
}

Quando tento criar o arquivo, eu recebo um erro de compilação dizendo The 'this' object cannot be used before all of its fields are assigned to. Isso pode ser resolvido alterando o construtor para fazer uma chamada acorrentado ao construtor padrão como este:

public Address(string line1, string line2, string city, string state, string zip): this()
{
    Line1 = line1;
    Line2 = line2;
    City = city;
    State = state;
    Zip = zip;
}

A minha pergunta é, por que este trabalho, eo que está acontecendo? Eu tenho um palpite, e eu tentei provar isso ao olhar para IL, mas eu só estou brincando comigo mesmo se eu acho que pode quebrar IL. Mas meu palpite é, as propriedades auto trabalhar por ter o compilador gerar campos para suas propriedades nos bastidores. Esses campos não podem ser acessados ??por meio de código, todas as definições e se deve ser feito através das propriedades. Ao criar uma estrutura, um construtor padrão pode não ser explicitamente definido. Então, nos bastidores, o compilador deve gerar um construtor padrão que define os valores dos campos que o desenvolvedor não pode ver.

Todas e quaisquer assistentes IL são bem-vindos para provar ou refutar minha teoria.

Foi útil?

Solução

Nota: a partir de C # 6, isso não é necessário - mas você deve estar usando propriedades somente leitura automaticamente implementados com C # 6 de qualquer maneira ...

this() garante que os campos são definitivamente atribuída, tanto quanto o compilador está em causa - ele define todos os campos para seus valores padrão. Você tem que ter uma estrutura totalmente construído antes que você possa começar a acessar qualquer propriedades.

É chato, mas essa é a maneira que é. Tem certeza de que quer realmente que este é um struct embora? E por que usar um setter protegido em um struct (que não pode ser derivada de)?

Outras dicas

A propriedade é nada mais do que um encapsulamento de um método Get e / ou um método Set. O CLR tem metadados que indica que os métodos particulares devem ser consideradas como sendo de propriedades, ou seja, deve permitir compiladores alguns constructos que não permitiriam com métodos. Por exemplo, se X é uma propriedade de leitura-escrita de Foo, um compilador irá traduzir Foo.X += 5 em Foo.SET_X_METHOD(Foo.GET_X_METHOD() + 5) (embora os métodos são nomeados de forma diferente, e não são geralmente acessíveis pelo nome).

Apesar de um autoproperty implementa um par de métodos get / set que acessam um campo particular de tal forma a se comportar mais ou menos como um campo, do ponto de vista de qualquer código fora da propriedade, uma autoproperty é um par de métodos get / set como qualquer outra propriedade. Consequentemente, uma declaração como Foo.X = 5; é traduzido como Foo.SET_X_METHOD(5). Desde o compilador C # só vê isso como uma chamada de método, e uma vez que os métodos não incluem quaisquer metadados para indicar quais os campos que ler ou escrever, o compilador irá proibir a chamada de método a menos que sabe todos os campos da Foo foi escrito.

Pessoalmente, o meu conselho seria para evitar o uso de autoproperties com tipos de estrutura. Autoproperties fazer sentido com aulas, já que é possível para propriedades de classe para recursos de suporte, como notificações de atualização. Mesmo que as primeiras versões de uma classe não suportam notificações de atualização, ter essas versões usam um autoproperty em vez de um campo significa que as versões futuras pode adicionar update-notificação apresenta sem a necessidade dos consumidores da classe a ser reformulado. Estruturas, no entanto, pode não significativamente apoiar a maioria dos tipos de características que se poderia desejar para adicionar ao campo-como propriedades.

Além disso, as diferenças de desempenho entre campos e propriedades é muito maior com grandes estruturas do que é com os tipos de classe. De fato, grande parte da recomendação de evitar grandes estruturas é uma consequência dessa diferença. grandes estruturas pode realmente ser muito eficiente, se se evita copiá-los desnecessariamente. Mesmo se um tinha uma enorme HexDecet<HexDecet<HexDecet<Integer>>> estrutura, onde HexDecet<T> continha campos expostos F0..F15 do tipo T, uma declaração como Foo = MyThing.F3.F6.F9; seria simplesmente exigir leitura de um número inteiro de MyThing e armazená-lo para Foo, embora MyThing seria pelo enorme pelos padrões struct ( 4096 inteiros ocupando 16K). Além disso, pode-se actualizar esse elemento muito facilmente, por exemplo MyThing.F3.F6.F9 += 26;. Em contrapartida, se F0..F15 eram auto-properties, o Foo = MyThing.F3.F6.F9 declaração exigiria copiando 1K de dados de MyThing.F3 a uma temporária (chamemos-lhe temp1, em seguida, 64 bytes de dados de temp1.F6 para temp2) antes de finalmente se locomover a ler 4 bytes de dados de temp2.F9. Ick. Pior, tentando adicionar 26 ao valor na MyThing.F3.F6.F9 exigiria algo como var t1 = MyThing.F3; var t2 = t1.F6; t2.F9 += 26; t1.F6 = f2; MyThing.F3 = t1;.

Muitas das queixas de longa data sobre "tipos de estrutura mutáveis" são realmente queixas sobre tipos de estrutura com propriedades de leitura / gravação. Basta substituir propriedades com campos e os problemas vão embora.

PS: Há momentos em que pode ser útil ter uma estrutura cujas propriedades acessar um objeto de classe ao qual ele mantém uma referência. Por exemplo, seria bom ter uma versão de uma classe ArraySegment<T> que permitiu a dizer Var foo[] = new int[100]; Var MyArrSeg = New ArraySegment<int>(foo, 25, 25); MyArrSeg[6] += 9;, e ter a última declaração add nove a elemento (25 + 6) de foo. Em versões anteriores do C # um poderia fazer isso. Infelizmente, o uso frequente de autoproperties no quadro onde os campos teria sido mais apropriado levou a queixas generalizadas sobre o compilador permitindo psetters ROPRIEDADE a ser chamado inutilmente em estruturas de somente leitura; consequentemente, chamar qualquer setter propriedade sobre uma estrutura de somente leitura é agora proibido, ou não a propriedade setter seria realmente modificar os campos da struct. Se as pessoas tivessem simplesmente absteve-se de fazer estruturas mutáveis ??via setters de propriedade (tornando campos diretamente acessível quando mutabilidade era apropriado) compiladores nunca teria tido a implementar essa restrição.

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