Estou usando propriedades implementadas automaticamente. Eu acho que a maneira mais rápida de corrigir o seguinte é declarar minha própria variável de backup?
public Point Origin { get; set; }
Origin.X = 10; // fails with CS1612
Mensagem de erro: Não é possível modificar o valor de retorno de 'expressão' porque não é uma variável
Foi feita uma tentativa de modificar um tipo de valor que era o resultado de uma expressão intermediária. Como o valor não é persistente, o valor não será alterado.
Para resolver esse erro, armazene o resultado da expressão em um valor intermediário ou use um tipo de referência para a expressão intermediária.
c#
variables
struct
immutability
Paulo
fonte
fonte
Respostas:
Isso ocorre porque
Point
é um tipo de valor (struct
).Por esse motivo, ao acessar a
Origin
propriedade, você está acessando uma cópia do valor mantido pela classe, e não o valor em si, como faria com um tipo de referência (class
); portanto, se você definir aX
propriedade nela, estará configurando a propriedade na cópia e, em seguida, descartá-la, mantendo o valor original inalterado. Provavelmente não é isso que você pretendia, e é por isso que o compilador está avisando sobre isso.Se você deseja alterar apenas o
X
valor, precisa fazer algo assim:fonte
Usar uma variável de apoio não ajudará.OPoint
tipo é um tipo de valor.Você precisa atribuir todo o valor do ponto à propriedade Origin:
O problema é que, quando você acessa a propriedade Origin, o que é retornado
get
é uma cópia da estrutura Point no campo criado automaticamente pelas propriedades Origin. Portanto, sua modificação do campo X nesta cópia não afetaria o campo subjacente. O compilador detecta isso e gera um erro, pois essa operação é totalmente inútil.Mesmo se você usou sua própria variável de apoio, sua
get
aparência seria: -Você ainda retornaria uma cópia da estrutura Point e obteria o mesmo erro.
Hmm ... depois de ler sua pergunta com mais cuidado, talvez você queira modificar a variável de apoio diretamente de sua classe: -
Sim, isso seria o que você precisaria.
fonte
Até agora você já sabe qual é a fonte do erro. Caso um construtor não exista com uma sobrecarga para ocupar sua propriedade (nesse caso
X
), você pode usar o inicializador de objetos (que fará toda a mágica nos bastidores). Não que você não precise imutar suas estruturas , mas apenas fornecendo informações adicionais:Isso é possível porque nos bastidores isso acontece:
Parece uma coisa muito estranha de se fazer, nem um pouco recomendada. Apenas listando uma maneira alternativa. A melhor maneira de fazer é tornar o struct imutável e fornecer um construtor adequado.
fonte
Origin.Y
? Dada uma propriedade do tipoPoint
, eu pensaria que a maneira idiomática de mudarX
seriavar temp=thing.Origin; temp.X = 23; thing.Origin = temp;
. A abordagem idiomática tem a vantagem de não precisar mencionar os membros que não deseja modificar, um recurso que só é possível porquePoint
é mutável. Estou intrigado com a filosofia que diz que, porque o compilador não pode permitir queOrigin.X = 23;
se deva projetar uma estrutura para exigir código comoOrigin.X = new Point(23, Origin.Y);
. O último parece realmente nojento para mim.X
eY
ao construtor específico). Agora, perde o ponto quando se pode fazerPoint p = new Point()
. Eu sei por que é realmente necessário para uma estrutura, então não faz sentido pensar nisso. Mas você tem uma ideia interessante de atualizar apenas uma propriedade comoX
?Object
. Eles não. Toda definição de tipo de valor realmente define dois tipos de coisas: um tipo de local de armazenamento (usado para variáveis, slots de matriz etc.) e um tipo de objeto de heap, às vezes chamado de tipo "em caixa" (usado quando um valor de tipo de valor é armazenado em um local do tipo de referência).Além de debater os prós e os contras de estruturas versus classes, costumo olhar para o objetivo e abordar o problema a partir dessa perspectiva.
Dito isto, se você não precisar escrever código por trás dos métodos get e set da propriedade (como no seu exemplo), não seria mais fácil simplesmente declarar o
Origin
campo como um campo da classe do que uma propriedade? Eu acho que isso permitiria que você atingisse seu objetivo.fonte
O problema é que você aponta para um valor localizado na pilha e o valor não será reconfigurado de volta para a propriedade orignal, portanto, o C # não permite retornar uma referência a um tipo de valor. Eu acho que você pode resolver isso removendo a propriedade Origin e, em vez disso, use um arquivo público, sim, eu sei que não é uma solução agradável. A outra solução é não usar o ponto e, em vez disso, criar seu próprio tipo de ponto como um objeto.
fonte
Point
for um membro de um tipo de referência, ele não estará na pilha, estará na pilha na memória do objeto que a contém.Eu acho que o problema aqui é que você está tentando atribuir subvalores do objeto na declaração, em vez de atribuir o próprio objeto. Você precisa atribuir o objeto Point inteiro nesse caso, pois o tipo de propriedade é Point.
Espero ter feito sentido lá
fonte
Point
fosse um tipo de classe mutável, o código original teria definido o campo ou a propriedadeX
no objeto retornado pela propriedadeOrigin
. Não vejo razão para acreditar que isso teria o efeito desejado sobre o objeto que contém aOrigin
propriedade. Algumas classes do Framework têm propriedades que copiam seu estado para novas instâncias de classe mutável e as retornam. Esse design tem a vantagem de permitir que o código comothing1.Origin = thing2.Origin;
defina o estado de origem do objeto para corresponder ao de outro, mas não pode alertar sobre o código comothing1.Origin.X += 4;
.Apenas remova a propriedade "get set" da seguinte maneira e tudo funcionará como sempre.
No caso de tipos primitivos, instread use o get; set; ...
fonte
Acho que muitas pessoas estão ficando confusas aqui, esse problema específico está relacionado ao entendimento de que as propriedades do tipo de valor retornam uma cópia do tipo de valor (como nos métodos e indexadores), e os campos do tipo de valor são acessados diretamente . O código a seguir faz exatamente o que você está tentando alcançar acessando diretamente o campo de apoio da propriedade (note: expressar uma propriedade em sua forma detalhada com um campo de apoio é o equivalente a uma propriedade automática, mas tem a vantagem de que em nosso código podemos acesse diretamente o campo de apoio):
O erro que você está recebendo é uma consequência indireta de não entender que uma propriedade retorna uma cópia de um tipo de valor. Se você receber uma cópia de um tipo de valor e não a atribuir a uma variável local, as alterações feitas nessa cópia nunca poderão ser lidas e, portanto, o compilador gera isso como um erro, pois isso não pode ser intencional. Se atribuirmos a cópia a uma variável local, podemos alterar o valor de X, mas ele será alterado apenas na cópia local, que corrige o erro do tempo de compilação, mas não terá o efeito desejado de modificar a propriedade Origin. O código a seguir ilustra isso, pois o erro de compilação desapareceu, mas a declaração de depuração falhará:
fonte