Por que não posso usar a palavra chave para um struct?
-
25-09-2019 - |
Pergunta
Eu definida a seguinte estrutura:
public struct Call
{
public SourceFile caller;
public SourceFile callee;
public Call(SourceFile caller, SourceFile callee)
{
this.caller = caller;
this.callee = callee;
}
}
Mais tarde, eu atribuir a ele a Marca de propriedade de outro objeto:
line.Tag = new Call(sf1, sf2);
Mas quando eu tento recuperar a propriedade Tag como assim,
Call call = line.Tag as Call;
O Visual Studio dá o seguinte erro de tempo de compilação:
O operador deve ser utilizado dentro de um tipo de referência ou tipo anulável
Qual é o significado disso?E como eu posso resolver isso?
Solução
Uma estrutura é um tipo de valor, portanto não pode ser usado com o as
operador. o as
O operador deve ser capaz de atribuir um valor de nulo se o elenco falhar. Isso só é possível com um tipo de referência ou um tipo de valor anulado.
Existem algumas maneiras de resolver isso, mas sua melhor aposta é mudar seu Call
digite de uma estrutura para uma classe. Isso mudará essencialmente o seu tipo de um tipo de valor para um tipo de referência, que permite o as
Operador para atribuir um valor de nulo se o elenco falhar.
Para mais informações sobre tipos de valor versus tipos de referência, isto é um artigo decente. Além disso, dê uma olhada no MSDN:
Outras dicas
Algumas das respostas existentes não são bastante certo. Você não pode usar não nulo tipos com as
, porque o resultado de as
é o valor nulo do tipo se o primeiro operando não for realmente do tipo apropriado.
No entanto, você posso usar as
com tipos de valor ... se eles são anuláveis:
int a = 10;
object o = a;
int? x = o as int?; // x is a Nullable<int> with value 10
long? y = o as long?; // y is a Nullable<long> with the null value
Então você poderia usar:
Call? call = line.Tag as Call?;
Então você pode usá -lo como:
if (call != null)
{
// Do stuff with call.Value
}
Duas advertências embora:
- Na minha experiência, isso é mais lento do que apenas usar
is
seguido de um elenco - Você deve reconsiderar seriamente seu atual
Call
modelo:- Está expondo campos públicos, que geralmente é fraco encapsulamento
- É um tipo de valor mutável, que é quase certamente um erro
Eu sugiro fortemente que você faça uma aula - em que ponto esse problema desaparece de qualquer maneira.
Outro pensamento: se a tag deve sempre ser um Call
, então é melhor lançá -lo:
Call call = (Call) line.Tag;
Dessa forma, se os dados não correspondem à sua expectativa (ou seja, há algum bug, de modo que o Tag
não é um Call
) Então você descobre isso mais cedo, e não depois de fazer algum outro trabalho. Observe que este elenco se comportará de maneira diferente, dependendo se Call
é uma estrutura ou uma classe, se Tag
é nulo - você pode lançar um valor nulo em uma variável de um tipo de referência (ou um tipo de valor anulado), mas não para um tipo de valor não indicado.
A partir do C# Spec
§7.10.11 O operador é usado para converter explicitamente um valor para um determinado tipo de referência ou tipo anulável.Ao contrário de um elenco de expressão (§7.7.6), o operador como nunca lança uma excepção.Em vez disso, se o indicado a conversão não é possível, o valor resultante é null.
Referências e tipos anuláveis podem ser null.Stucts são tipos de valor, de modo que eles não podem ser nulos.
Call? call = line.Tag as Call?;
É uma limitação de C#. Se o tipo fosse um tipo de referência, se o elenco falhar, ele simplesmente retornaria 'nulo', mas como é um tipo de valor, não sabe o que retornar quando o elenco falhar.
Você deve substituir o uso de dois: 'é' e 'como'
if (line.Tag is Call) {
call = (Call)line.Tag;
} else {
// Do whatever you would do if as returned null.
}
Qual é o significado - como indicado, as estruturas são tipos de valor.
Como posso resolvê -lo - mude para
Call call = line.Tag;