Pergunta

Alguém pode esclarecer o C # is palavra-chave agradar. Em particular estas 2 perguntas:

Q1) linha 5; Por que esse retorno verdade?

Q2) linha 7; Por que nenhuma exceção elenco?

public void Test()
{
    object intArray = new int[] { -100, -200 };            

    if (intArray is uint[]) //why does this return true?
    {
        uint[] uintArray = (uint[])intArray; //why no class cast exception?

        for (int x = 0; x < uintArray.Length; x++)
        {
            Console.Out.WriteLine(uintArray[x]);
        }
    }
}

A descrição de MSDN não esclarece a situação. Ele afirma que is retornará true se qualquer uma destas condições sejam atendidas. (Http://msdn.microsoft.com/en-us/library/scekt9xw(VS.71).aspx>MDSN artigo)

expression is not null.
expression can be cast to type.

Eu não acredito que você pode fazer um elenco válida de int [] em uint []. Porque:

A) Este código não compila:

int[] signed = new int[] { -100 };
uint[] unsigned = (uint[])signed; 

B) Fazer o elenco no depurador dá um erro:

(uint[])signed
"Cannot convert type 'int[]' to 'uint[]'"

Com certeza, se a linha 3 foi int [] em vez de objeto, em seguida, ele nunca seria compilar. O que me leva a uma pergunta final relacionado à Q2.

Q3) Por que o C # raise um erro de elenco / conversão no depurador e compilador, mas não em tempo de execução?

Foi útil?

Solução

C # e do CLR tem regras de conversão tanto diferentes.

Você não pode diretamente elenco entre int[] e uint[] em C #, porque o idioma não acredita que qualquer conversão está disponível. No entanto, se você ir via object o resultado está à altura da CLI. De seção do CLI especificação 8.7 (espero - Estou citando um troca de e-mail que eu tinha sobre este tema com Eric Lippert um tempo atrás):

Assinado e integral sem sinal primitivo tipos pode ser atribuído a outro; por exemplo, int8: = uint8 é válido. Por esta propósito, bool será considerada compatível com uint8 e vice-versa, o que torna bool := uint8 válido e vice-versa. Isto também é verdade para matrizes de integrante assinados e não assinados tipos de primitivas do mesmo tamanho; por exemplo, int32[] := uint32[] é válido.

(eu não marcada, mas presumo que esse tipo de conversão de tipo de referência sendo válido é o que faz retorno is verdade também.)

É um pouco lamentável que existem desconexões entre a linguagem eo mecanismo de execução subjacente, mas é praticamente inevitável, a longo prazo, eu suspeito. Existem alguns outros casos como este, mas a boa notícia é que eles raramente parecem causar danos significativos.

EDIT:. Como Marc eliminado sua resposta, eu ligado ao correio electrónico completo de Eric, como afixado ao C # newsgroup

Outras dicas

Agora que é interessante. Achei isso no padrão ECMA-335. 4,3 castclass. Note-se que:

  • Arrays herdar de System.Array.

  • Se Foo pode ser convertido para Bar, em seguida, Foo [] pode ser convertido para Bar [].

  • Para efeitos da nota 2 acima, enums são tratados como seu tipo subjacente:., Assim, E1 [] pode ser convertido para E2 [] se E1 e E2 compartilham um tipo subjacente

Você pode lançar int para uint, mas que ele se comporta como este é muito estranho. O Visual Studio não reconhece nada disso, até mesmo o relógio, quando o depurador é anexado apenas mostra um ponto de interrogação '?'.

Você pode querer dar uma olhada em este , avançar cerca de 10 minutos em e ouvir Anders explicar a implementação de array co-variante. Eu acho que é a questão fundamental subjacente aqui.

Sugestão:

Declarando intArray como "int [] intArray" em vez de "objeto intArray" permitirá que o compilador para pegar o C # elenco inválido. A menos que seja absolutamente necessário usar objeto, gostaria de aproveitar essa abordagem.

Re Q2, Q3:

Em tempo de execução você já tentou envolver o elenco em um verificado bloco?

A partir deste artigo no MSDN:

Por padrão, uma expressão que contém apenas os valores constantes provoca um compilador de erro se a expressão produz um valor que está fora do intervalo do tipo de destino. Se o expressão contém um ou mais valores não constantes, o compilador faz não detectar o excesso.

...

Por padrão, eles não constante expressões não são verificadas para estouro em tempo de execução, quer, e eles não levantam estouro exceções. o Exemplo de telas anteriores -2147483639 como a soma de dois inteiros positivos.

Overflow verificação pode ser ativado por opções do compilador, meio ambiente configuração ou uso do verificado palavra-chave.

Como diz, você pode impor verificação de estouro mais globalmente através de uma configuração compilador ou ambiente de configuração.

No seu caso esta é provavelmente desejável, pois fará com que um erro de execução a ser jogado que irá garantir que o número não assinado inválido provável que o número assinado estouro não ocorrerá em silêncio.

[Update] Depois de testar este código, eu achei que o uso de uma declaração de tipo de objeto em vez de int [] aparece para ignorar o sytax C # fundição padrão, independentemente se verificado está habilitado ou não.

Como JS disse, quando você usa objeto, você é obrigado por regras CLI e estes aparentemente permitir que isso ocorra.

Re Q1:

Isto está relacionado com o acima. Em suma, porque o elenco envolvido não lançar uma exceção (com base na configuração de excesso de corrente). Se isto é uma boa ideia é outra questão.

De MSDN :

Um "é", avalia expressão para true se a expressão fornecida não é nulo, ea fornecida objecto pode ser convertido para o tipo fornecido sem causar uma excepção a ser lançada.

Eu estou supondo trás compatablility com NET 1: Eu ainda estou um pouco confuso sobre os detalhes, mas eu acredito que o tipo de CLR de todas as matrizes é simplesmente System.Array, com propriedades do tipo extra para procurar o tipo de elemento. 'É' provavelmente só não conta para que, em CLR v1, e agora deve manter isso.

Não funciona no caso (uint[])(new int[]{}) é provavelmente devido ao compilador C # (não o tempo de execução CLR) ser capaz de fazer typechecking mais rigorosa.

Além disso, as matrizes são apenas digitar inseguro em geral:

Animal[] tigers = new Tiger[10];
tigers[3] = new Elephant(); // ArrayTypeMismatchException

OK,

I tentar tomar uma facada nisso.

Primeiro, a documentação diz: "Verifica se um objeto é compatível com um determinado tipo.", Diz também que se o tipo da esquerda é "refratário" (você pode converter sem exceção) para o tipo no certo, e os avalia expressão a não-nulo, o "é" palavra-chave irá avaliar a true.

Olhe para Jon Skeet para a outra resposta. Ele disse que mais eloquente do que eu poderia. Ele está certo, se uma conversão estiver disponível, ele irá aceitar a sua sintaxe, você poderia posteriormente escrever o seu próprio, mas parece um exagero nesta situação.

Referência: http://msdn.microsoft. com / en-us / library / scekt9xw (VS.80) .aspx

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