¿Por qué puedo pasar 1 como un corto, pero no la variable int i?

146

¿Por qué funcionan la primera y la segunda escritura pero no la última? ¿Hay alguna forma en que pueda permitir a los 3 y detectar si fue 1, (int) 1 o si pasé? ¿Y realmente por qué se permite uno pero el último? El segundo permitido pero no el último realmente me deja sin aliento.

Demostración para mostrar el error de compilación

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
fuente
2
Yo también estoy perplejo por esto, a menudo tengo que hacer ints para acortar las llamadas a funciones, aunque deberían ser moldeables ...
Mathieu Dumoulin
2
@MathieuDumoulin son moldeables, por eso puedes lanzarlos. Pero es una conversión con pérdida (hay muchas entradas que no caben en un corto), por lo que no es posible la conversión implícita, por eso hay que escribir (short) i.
Abel

Respuestas:

186

Las dos primeras son expresiones constantes, la última no.

La especificación C # permite una conversión implícita de int a short para constantes, pero no para otras expresiones. Esta es una regla razonable, ya que para las constantes el compilador puede garantizar que el valor se ajuste al tipo de destino, pero no puede para las expresiones normales.

Esta regla está en línea con la directriz de que las conversiones implícitas no deberían tener pérdidas.

6.1.8 Conversiones implícitas de expresión constante

Una conversión de expresión constante implícita permite las siguientes conversiones:

  • Una expresión-constante (§7.18) de tipo intse puede convertir en tipo sbyte, byte, short, ushort, uint, o ulong, siempre que el valor de la constante-expresión está dentro del rango del tipo de destino.
  • Una expresión constante de tipo longse puede convertir a tipo ulong, siempre que el valor de la expresión constante no sea negativo.

(Citado de C # Language Specification Version 3.0)

CodesInChaos
fuente
67

No hay conversión implícita de inta shortdebido a la posibilidad de truncamiento. Sin embargo, el compilador puede tratar una expresión constante como del tipo de destino .

1? No es un problema: es claramente un shortvalor válido . i? No tanto, podría ser algún valor> short.MaxValuepor ejemplo, y el compilador no puede verificar eso en el caso general.

Konrad Rudolph
fuente
Entonces ... no importa cuán explícito sea ...> _ <. ¿Tienes alguna idea si puedo detectar si se pasó un litereal o una variable int?
@ acidzombie24 No puedes. ¿Pero por qué querrías hacer eso?
Adam Houldsworth
@ acidzombie24 No creo que puedas detectar eso. Usted puede sin embargo utilizar un argumento de plantilla y luego utilizar la reflexión para llegar a su tipo.
Konrad Rudolph
3
@ acidzombie24 No hay forma de que se pueda pasar un literal durante el tiempo de ejecución. Así que puedes usar tus ojos para verificar en tiempo de compilación.
Justin
1
@ acidzombie24 En ese caso, ¿sería una opción aceptar el argumento como un Expression<Func<int>>? Luego podría pasar () => 1o () => identro de la función y podría inspeccionar si la entidad pasada contenía una variable capturada o un valor constante.
Konrad Rudolph
8

un int literal se puede convertir implícitamente a short. Mientras:

No puede convertir implícitamente tipos numéricos no literales de mayor tamaño de almacenamiento a cortos

Entonces, los dos primeros funcionan porque se permite la conversión implícita de literales.

Damien_The_Unbeliever
fuente
3
Tu respuesta es un poco incorrecta. No debes usar expresiones literales sino constantes . En particular, el segundo ejemplo no es un literal .
CodesInChaos
6

Creo que es porque está pasando literal / constante en los dos primeros, pero no hay conversión de tipo automática al pasar un número entero en el tercero.

Editar: ¡Alguien me ganó!

Justin
fuente
3

Porque no habrá ninguna conversión implícita entre el tipo no literal a un tamaño más corto.

La conversión implícita solo es posible para la expresión constante.

public static void Write(short v) { }

Donde como estás pasando integervalor como argumento parashort

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

El compilador le ha dicho por qué falla el código:

cannot convert `int' expression to type `short'

Entonces, esta es la pregunta que debe hacerse: ¿por qué falla esta conversión? Busqué en Google "c # convert int short" y terminé en la página de MS C # para la shortpalabra clave:

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

Como dice esta página, las conversiones implícitas de un tipo de datos más grande shortsolo se permiten para literales. El compilador puede saber cuándo un literal está fuera de rango, pero no de otra manera, por lo que necesita asegurarse de que ha evitado un error de fuera de rango en la lógica de su programa. Esa tranquilidad es proporcionada por un elenco.

Write((short)i)
Isaac Rabinovitch
fuente
0

La conversión de int -> short puede provocar el truncamiento de datos. Es por eso.

ak1238
fuente