Pergunta

CS0283 indica que apenas o tipos básicos de PI (assim como cordas, enums, e referências nulas) podem ser declarados como const. Alguém tem uma teoria sobre a razão para essa limitação? Por exemplo, seria bom ser capaz de declarar valores const de outros tipos, tais como IntPtr.

Eu acredito que o conceito de const é realmente açúcar sintático em C #, e que apenas substitui quaisquer usos do nome com o valor literal. Por exemplo, dada a seguinte declaração, qualquer referência ao Foo seria substituída por "foo" em tempo de compilação.

const string Foo = "foo";

Este seria afastar quaisquer tipos mutáveis, talvez por isso eles escolheram esta limitação ao invés de ter de determinar em tempo de compilação se um determinado tipo é mutável?

Foi útil?

Solução

A partir dos C # especificação, capítulo 10.4 - Constantes :
(10,4 na especificação C # 3.0, 10.3 na versão on-line para 2.0)

Uma constante é um membro da classe que representa um valor constante:. Um valor que pode ser calculado em tempo de compilação

Isso basicamente diz que você só pode usar expressões que consiste unicamente em literais. Todas as chamadas para quaisquer métodos, construtores (que não podem ser representados como literais IL puros) não pode ser usado, como não há nenhuma maneira para que o compilador para fazer isso execução, e, assim, calcular os resultados, em tempo de compilação. Além disso, uma vez que não há maneira de etiquetar um método como invariante (isto é., Há um mapeamento um-para-um entre a entrada e saída), a única maneira para o compilador para fazer isto seria quer analisar a IL para ver se isso depende de outros do que os parâmetros de entrada, especial-caso lidar com alguns tipos (como IntPtr) as coisas, ou apenas não permitir todas as chamadas para qualquer código.

IntPtr, como um exemplo, apesar de ser um tipo de valor, ainda é uma estrutura, e não um do embutido literais. Como tal, qualquer expressão utilizando um IntPtr precisará chamar o código na estrutura IntPtr, e é isso que não é legal de declaração constante.

O exemplo tipo de valor constante só é legal que eu posso pensar seria aquele que é inicializado com zeros por apenas declará-lo, e isso é pouco útil.

Quanto à forma como o compilador trata / usos constantes, ele usará o valor calculado no lugar do nome constante no código.

Assim, você tem o seguinte efeito:

  • Nenhuma referência ao nome constante original, classe que foi declarada em, ou namespace, é compilado para o código neste local
  • Se você descompilar o código, terá números mágicos nele, simplesmente porque a "referência" original para o constante é, como mencionado acima, não está presente, apenas o valor da constante
  • O compilador pode usar isso para otimizar, ou até mesmo eliminar, código desnecessário. Por exemplo, if (SomeClass.Version == 1), quando SomeClass.Version tem o valor de 1, vai de fato remover a instrução if-e manter o bloco de código que está sendo executado. Se o valor da constante não é 1, o conjunto se-declaração e seu bloco será removido.
  • Uma vez que o valor de uma constante é compilado para o código, e não uma referência para a constante, usando constantes de outros conjuntos não vai automagicamente atualizar o código compilado de qualquer forma, se o valor da constante deve mudar (que deveria não!)

Em outras palavras, com o seguinte cenário:

  1. Assembly A, contém uma constante chamada "Version", com um valor de 1
  2. Assembleia B, contém uma expressão que analisa o número de versão do assembly A partir desse constante e compara-o a 1, para se certificar de que ele possa trabalhar com a montagem
  3. modifica alguém conjunto A, aumentando o valor da constante a 2, e reconstrói um (mas não B)

Neste caso, o conjunto B, na sua forma compilada, irá ainda comparar o valor de 1 para 1, porque quando B foi compilado, a constante tinha o valor 1.

De facto, se esta é a única utilização de qualquer coisa de montagem A em conjunto B, B montagem será compilado sem uma dependência em conjunto A. executar o código que contenha essa expressão em conjunto B não será carregado montagem A.

Constantes devem, portanto, ser usado apenas para coisas que nunca vão mudar. Se é um valor que pode ou vai mudar em algum momento no futuro, e você não pode garantir que todos os outros conjuntos são reconstruídos, simultaneamente, um campo somente leitura é mais apropriado do que uma constante.

Então, isso é ok:

  • const pública Int32 NumberOfDaysInAWeekInGregorianCalendar = 7;
  • const pública Int32 NumberOfHoursInADayOnEarth = 24;

enquanto isso não é:

  • const pública Int32AgeOfProgrammer = 25;
  • const public String NameOfLastProgrammerThatModifiedAssembly = "Joe programador";

Editar 27 de maio de 2016

OK, só tenho um upvote, então eu re-ler a minha resposta aqui e este é realmente um pouco errado.

Agora, a intenção da especificação da linguagem C # é tudo o que eu escrevi acima. Você não deveria usar algo que não pode ser representado com uma literal como um const.

Mas pode? Bem, sim ....

Vamos dar uma olhada no tipo decimal.

public class Test
{
    public const decimal Value = 10.123M;
}

Vamos olhar o que este classe olhares como realmente quando olhou com ildasm:

.field public static initonly valuetype [mscorlib]System.Decimal X
.custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(int8, uint8, uint32, uint32, uint32) = ( 01 00 01 00 00 00 00 00 00 00 00 00 64 00 00 00 00 00 ) 

Deixe-me quebrá-lo para baixo para você:

.field public static initonly

corresponde a:

public static readonly

É isso mesmo, um const decimal é realmente um readonly decimal.

O negócio real aqui é que o compilador usará essa DecimalConstantAttribute para trabalhar sua mágica.

Agora, esta é a única tal magia que eu conheço com o compilador C #, mas eu pensei que era vale a pena mencionar.

Outras dicas

Alguém tem uma teoria sobre a razão para essa limitação?

Se for permitido ser apenas uma teoria, a minha teoria é que os valores const de tipos primitivos pode ser expressa em parâmetros opcode literais na MSIL ... mas os valores de outros tipos, não-primitivos não pode, porque MSIL doesn' t têm a sintaxe para expressar o valor de um tipo definido pelo usuário como um literal.

Eu acredito que o conceito de const é realmente açúcar sintático em C #, e que apenas substitui quaisquer usos do nome com o valor literal

O que o compilador fazer com objetos const em outros idiomas?

Você pode usar somente leitura para os tipos mutáveis ??que me ser avaliadas em tempo de execução. Consulte este artigo para as diferenças.

consts são limitadas a números e strings em C # porque o compilador substitui a variável com o valor literal na MSIL. Em outras palavras, quando você escreve:

const string myName = "Bruce Wayne";
if (someVar == myName)
{
   ...
}

é realmente tratado como

if (someVar == "Bruce Wayne")
{
   ...
}

e sim, o compilador C # é inteligente o suficiente para tratar o operador de igualdade (==) em strings como

string1.Equals(string2)

Parece-me que apenas os tipos de valor pode ser expresso como uma constante (com exceção de cordas, que fica em algum lugar entre o valor eo tipo de objeto).

É OK para mim:. Objetos (referências) deve ser alocada na pilha, mas constantes não são atribuídos a todos (uma vez que eles são substituídos em tempo de compilação)

Em suma, todos os tipos simples, enums e strings são imutáveis, mas uma estrutura, por exemplo, não é. Você pode ter uma estrutura com estado mutável (campos, propriedades, até mesmo as referências a tipos de referência). Portanto, o compilador não pode certificar-se (em tempo de compilação) que o estado interno de uma variável Struct não pode ser alterado. Assim, o compilador precisa ter certeza de que um tipo é de imutável definição para ser usado em uma expressão constante.

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