valor enum incorreto em C # [duplicado]
Por que a impressão a seguir EOFé a saída e não ILLEGAL? Se eu remover a inicialização do caractere EOF para NULL, ele funcionará conforme o esperado. Não consegue entender o que está acontecendo aqui?
public enum TokenType {
ILLEGAL,
EOF= '\0',//remove the initialization to have it work as expected
IDENT,
INT
};
void Main()
{
Console.WriteLine(TokenType.ILLEGAL);//Prints EOF. Should have printed ILLEGAL
}
Respostas
Primeiro, observe que = '\0'é o mesmo que = 0. Isso ocorre porque '\0'tem o valor numérico de 0. Seu enum tem o tipo subjacente padrão de int. A expressão constante '\0'é convertida em intde 0em tempo de compilação.
Em segundo lugar, de acordo com as especificações do idioma , observe que os membros enum podem ter valores associados duplicados.
Terceiro, da mesma seção da especificação do idioma,
O valor associado de um membro enum é atribuído implícita ou explicitamente. [...] Se a declaração do membro enum não tiver inicializador, seu valor associado é definido implicitamente, como segue:
Se o membro enum for o primeiro membro enum declarado no tipo enum, seu valor associado será zero.
Caso contrário, o valor associado do membro enum é obtido aumentando o valor associado do membro enum textualmente anterior em um. Este valor aumentado deve estar dentro da faixa de valores que podem ser representados pelo tipo subjacente, caso contrário, ocorrerá um erro em tempo de compilação.
Então, se eu fosse escrever os valores associados dos membros do seu enum explicitamente, seria:
public enum TokenType {
ILLEGAL = 0,
EOF = 0,
IDENT = 1,
INT = 2
};
ILLEGALe EOFtêm o mesmo valor associado.
Quarto, Console.WriteLinechama ToStringseu enum. Agora veja o que Enum.ToStringfaz (na seção Notas para chamadores):
Se vários membros de enumeração tiverem o mesmo valor subjacente e você tentar recuperar a representação de seqüência de caracteres do nome de um membro de enumeração com base em seu valor subjacente, seu código não deve fazer suposições sobre qual nome o método retornará.
Portanto, a saída ILLEGALé completamente normal, já que você "não deve fazer nenhuma suposição sobre qual nome o método retornará".
Inicializando o EOFvalor com '\ 0', você atribui a ele o valor 0.
Você pode ver isso neste exemplo:
Console.WriteLine(Convert.ToInt16(TokenType.EOF));
Console.WriteLine($"IntValue: {Convert.ToInt16('\0')}");
0
IntValue: 0
Internamente, o enum obterá valores a partir de 0 na contagem ascendente em inteiros. Então, abaixo da superfície, seu enum é assim:
public enum TokenType
{
ILLEGAL = 0,
EOF = 1
IDENT = 2,
INT = 3
};
Mas você optou por impor um 0sobre o valor EOF! Portanto, você tem 2 nomes de enum que representam o mesmo valor. O compilador simplesmente pega o primeiro que puder encontrar.
isso explica a situação
foreach (Enum e in Enum.GetValues(typeof(TokenType)))
Console.WriteLine("{0}: {1}", e, Convert.ToInt16(e));
Console.WriteLine();
foreach (Enum e in Enum.GetValues(typeof(Another_TokenType)))
Console.WriteLine("{0}: {1}", e, Convert.ToInt16(e));
EOF: 0
EOF: 0
IDENT: 1
INT: 2
ILLEGAL: 0
ILLEGAL: 0
EOF: 1
IDENT: 2
'\ 0' leva ao valor 0 quando convertido para int. e o primeiro sinalizador de enum não inicializado com valor também tem valor 0.