Por que posso passar 1 como uma variável curta, mas não a variável int i?

146

Por que a primeira e a segunda gravação funcionam, mas não a última? Existe uma maneira de permitir todos os 3 e detectar se foi 1, (int) 1 ou eu passei? E realmente por que um é permitido, mas o último? O segundo sendo permitido, mas não o último, realmente me impressiona.

Demonstração para mostrar erro de compilação

using System;
class Program
{
    public static void Write(short v) { }
    static void Main(string[] args)
    {
        Write(1);//ok
        Write((int)1);//ok
        int i=1;
        Write(i);//error!?
    }
}
CodesInChaos
fonte
2
Eu também estou perplexo com isso, eu muitas vezes têm de ints elenco para curta em chamadas de função, embora eles devem ser concreto ...
Mathieu Dumoulin
2
@MathieuDumoulin eles são castáveis, é por isso que você pode lançá-los. Mas é uma conversão sem perdas (existem muitas entradas que não cabem em um curto), portanto, elenco implícito não é possível, é por isso que você precisa escrever (short) i.
Abel

Respostas:

186

Os dois primeiros são expressões constantes, o último não.

A especificação C # permite uma conversão implícita de int para abreviação de constantes, mas não para outras expressões. Essa é uma regra razoável, pois para constantes, o compilador pode garantir que o valor se encaixe no tipo de destino, mas não para expressões normais.

Esta regra está alinhada com a diretriz de que conversões implícitas devem ser sem perdas.

6.1.8 Conversões implícitas de expressão constante

Uma conversão implícita de expressão constante permite as seguintes conversões:

  • Uma expressão constante (§7.18) de tipo intpode ser convertido no tipo sbyte, byte, short, ushort, uint, ou ulong, desde que o valor da constante de expressão está dentro do intervalo do tipo de destino.
  • Uma expressão constante do tipo longpode ser convertida em tipo ulong, desde que o valor da expressão constante não seja negativo.

(Citado em C # Language Specification versão 3.0)

CodesInChaos
fonte
67

Não há conversão implícita de intpara shortdevido à possibilidade de truncamento. No entanto, uma expressão constante pode ser tratada como sendo do tipo de destino pelo compilador .

1? Não é um problema: é claramente um shortvalor válido . i? Nem tanto - pode haver algum valor> short.MaxValuepor exemplo, e o compilador não pode verificar isso no caso geral.

Konrad Rudolph
fonte
Então ... não importa o quão explícito eu seja ...> _ <. Você tem alguma idéia se eu posso detectar se um litereal foi aprovado ou uma variável int?
@ acidzombie24 Você não pode. Mas porque você iria querer fazer aquilo?
Adam Houldsworth
@ acidzombie24 Acho que você não consegue detectar isso. No entanto, você pode usar um argumento de modelo e, em seguida, usar reflexão para obter seu tipo.
11289 Konrad Rudolph
3
@ acidzombie24 Não há como passar um literal durante o tempo de execução. Então você pode usar seus olhos para verificar em tempo de compilação.
11117 Justin
1
@ acidzombie24 Nesse caso, seria uma opção aceitar o argumento como um Expression<Func<int>>? Em seguida, você pode passar () => 1ou () => ie dentro da função você pode inspecionar se a entidade passada continha uma variável capturada ou um valor constante.
21430 Konrad Rudolph
8

um int literal pode ser implicitamente convertido em short. Enquanto que:

Você não pode converter implicitamente tipos numéricos não literais de tamanho de armazenamento maior para curto

Portanto, os dois primeiros funcionam porque a conversão implícita de literais é permitida.

Damien_The_Unbeliever
fonte
3
Sua resposta está um pouco errada. Você não deve usar expressão literal, mas constante . Em particular, o segundo exemplo não é literal .
CodesInChaos 11/07
6

Eu acredito que é porque você está passando literal / constante nos dois primeiros, mas não há conversão automática de tipo ao passar um número inteiro no terceiro.

Edit: Alguém me venceu a isso!

Justin
fonte
3

Porque não haverá conversão implícita entre o tipo Não Literal e o tamanho menor .

A conversão implícita é possível apenas para expressão constante.

public static void Write(short v) { }

Onde você está passando integervalor como argumento parashort

int i=1;
Write(i);  //Which is Nonliteral here
Vishal Suthar
fonte
3

O compilador lhe disse por que o código falha:

cannot convert `int' expression to type `short'

Então, eis a pergunta que você deve fazer: por que essa conversão falha? Pesquisei "c # convert int short" e acabei na página do MS C # da shortpalavra-chave:

http://msdn.microsoft.com/en-us/library/ybs77ex4(v=vs.71).aspx

Como diz esta página, as transmissões implícitas de um tipo de dados maior shortsão permitidas apenas para literais. O compilador pode dizer quando um literal está fora do intervalo, mas não o contrário, portanto, é necessário garantir que você evitou um erro fora do intervalo na lógica do programa. Essa garantia é fornecida por um elenco.

Write((short)i)
Isaac Rabinovitch
fonte
0

A conversão de int -> short pode resultar em truncamento de dados. É por isso.

ak1238
fonte