example - cast int c#
¿Por qué "int[] es uint[]== verdadero" en C# (5)
¿Alguien puede aclarar la C # is
palabra clave por favor? En particular estas 2 preguntas:
Q1) línea 5; ¿Por qué esto es verdad?
Q2) línea 7; ¿Por qué no hay excepción de lanzamiento?
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]);
}
}
}
La descripción de MSDN no aclara la situación. Establece que será verdadero si se cumplen cualquiera de estas condiciones. (http://msdn.microsoft.com/en-us/library/scekt9xw(VS.71).aspx>MDSN Article)
expression is not null. expression can be cast to type.
No creo que puedas hacer un lanzamiento válido de int [] en uint []. Porque:
A) Este código no se compila:
int[] signed = new int[] { -100 };
uint[] unsigned = (uint[])signed;
B) Hacer el yeso en el depurador da un error:
(uint[])signed
"Cannot convert type ''int[]'' to ''uint[]''"
Efectivamente, si la línea 3 fuera int [] en lugar de objeto, entonces nunca se compilaría. Lo que me lleva a una pregunta final relacionada con la Q2.
Q3) ¿Por qué C # genera un error de conversión / conversión en el depurador y el compilador pero no en el tiempo de ejecución?
C # y CLR tienen reglas de conversión algo diferentes.
No se puede convertir directamente entre int[]
y uint[]
en C # porque el idioma no cree que haya ninguna conversión disponible. Sin embargo, si va a través de un object
el resultado depende de la CLI. De la sección de especificaciones CLI 8.7 (espero, estoy citando un intercambio de correos electrónicos que tuve sobre este tema con Eric Lippert hace un tiempo):
Los primitivos integrales firmados y no firmados se pueden asignar el uno al otro; por ejemplo, int8: = uint8 es válido. Para este propósito, bool se considerará compatible con
uint8
y viceversa, lo que hace quebool := uint8
válido, y viceversa. Esto también es válido para matrices de tipos primitivos integrales con signo y sin signo del mismo tamaño; por ejemplo,int32[] := uint32[]
es válido.
(No lo he comprobado, pero asumo que este tipo de conversión de tipo de referencia es válida, lo que hace is
devolución sea verdadera también).
Es algo desafortunado que haya desconexiones entre el lenguaje y el motor de ejecución subyacente, pero es bastante inevitable a la larga, sospecho. Hay algunos otros casos como este, pero la buena noticia es que rara vez parecen causar un daño significativo.
EDITAR: Cuando Marc borró su respuesta, me he vinculado al correo completo de Eric, tal como se publicó en el grupo de noticias C #.
DE ACUERDO,
Intento dar una puñalada a esto.
En primer lugar, la documentación dice: "Comprueba si un objeto es compatible con un tipo determinado". También dice que SI el tipo de la izquierda es "moldeable" (puede convertir sin excepción) al tipo de la derecha, y la expresión se evalúa como no nula, la palabra clave "es" se evaluará como true
.
Mira a Jon Skeet por la otra respuesta. Él lo dijo más elocuentemente que yo. Tiene razón, si hay una conversión disponible, aceptará su sintaxis, luego podría escribir la suya propia, pero parecería excesivo en esta situación.
Referencia: http://msdn.microsoft.com/en-us/library/scekt9xw(VS.80).aspx
Estoy adivinando la compatibilidad con .NET 1: todavía estoy un poco confuso sobre los detalles, pero creo que el tipo CLR de todas las matrices es simplemente System.Array, con propiedades adicionales para buscar el tipo de elemento. ''es'' probablemente no explicaba eso en CLR v1, y ahora debe mantener eso.
No funciona en el caso (uint[])(new int[]{})
probablemente se deba al compilador de C # (no al tiempo de ejecución de CLR) que puede hacer una comprobación de tipo más estricta.
Además, las matrices simplemente escriben inseguras en general:
Animal[] tigers = new Tiger[10];
tigers[3] = new Elephant(); // ArrayTypeMismatchException
Sugerencia:
Declarar intArray como "int [] intArray" en lugar de "object intArray" permitirá al compilador recoger el molde de C # no válido. A menos que sea absolutamente necesario usar un objeto, tomaría ese enfoque.
Re Q2, Q3:
¿En tiempo de ejecución has intentado envolver el molde en un bloque marcado ?
De este artículo en MSDN:
De forma predeterminada, una expresión que contiene solo valores constantes causa un error de compilación si la expresión produce un valor que está fuera del rango del tipo de destino. Si la expresión contiene uno o más valores no constantes, el compilador no detecta el desbordamiento.
...
De forma predeterminada, estas expresiones no constantes no se verifican para el desbordamiento en el tiempo de ejecución tampoco, y no generan excepciones de desbordamiento. El ejemplo anterior muestra -2,147,483,639 como la suma de dos enteros positivos.
La verificación de desbordamiento puede habilitarse mediante las opciones del compilador, la configuración del entorno o el uso de la palabra clave verificada.
Como se dice, puede aplicar la verificación de desbordamiento de forma más global a través de una configuración de compilación o configuración de entorno.
En su caso, esto es probablemente deseable, ya que provocará un error en el tiempo de ejecución que garantizará que el probable número no válido no firmado para el desbordamiento del número firmado no se produzca de forma silenciosa.
[Actualizar] Después de probar este código, descubrí que el uso de una declaración de tipo de objeto en lugar de int [] parece omitir el sintaxis de conversión C # estándar, independientemente de si está activada o no.
Como dijo JS, cuando usas object, estás obligado por las reglas de CLI y aparentemente permiten que esto ocurra.
Re Q1:
Esto está relacionado con lo anterior. En resumen, dado que el elenco involucrado no arroja una excepción (según la configuración de desbordamiento actual). Si esta es una buena idea es otra pregunta.
Una expresión "es" se evalúa como verdadera si la expresión proporcionada no es nula y el objeto proporcionado se puede convertir al tipo proporcionado sin causar una excepción.
Ahora eso es interesante. Encontré esto en el estándar ECMA-335. 4.3 clase de cast. Tenga en cuenta que:
Las matrices heredan de System.Array.
Si Foo puede ser lanzado a Bar, entonces Foo [] puede ser lanzado a Bar [].
A los fines de la nota 2 anterior, las enumeraciones se tratan como su tipo subyacente: así E1 [] se puede convertir a E2 [] si E1 y E2 comparten un tipo subyacente.
Puedes lanzar int a uint, pero que se comporte así es muy extraño. Visual Studio no reconoce nada de esto, incluso el reloj, cuando el depurador está conectado solo muestra un signo de interrogación ''?''.
Puede echarle un vistazo a esto , adelantar unos 10 minutos y escuchar a Anders explicar la implementación de la matriz covariante. Creo que ese es el problema subyacente fundamental aquí.