Pregunta

He creado el siguiente propiedad, lo que arrojó un InvalidCastException si se accedió al comprador cuando era ViewState[TOTAL_RECORD_COUNT] null.

public long TotalRecordCount
{
    get { return (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1); }
    set { ViewState[TOTAL_RECORD_COUNT] = value; }
}

Mi pensamiento es que se trató de forma incorrecta desempacar el objeto en ViewState[TOTAL_RECORD_COUNT] a un int, que fracasó debido a que contenía un long, pero creo que podría haber un fallo en esa lógica. Voy a dejarlo como un ejercicio para el lector señalar que falla.

ya que he cambiado esa propiedad para leer

public long TotalRecordCount
{
    get { return (long?)ViewState[TOTAL_RECORD_COUNT] ?? -1; }
    set { ViewState[TOTAL_RECORD_COUNT] = value; }
}

Su funcionamiento es hincharse. Aún así, me quedo preguntando lo que estaba mal con mi versión original ... Stackoverflow al rescate?

Tenga en cuenta que si trato de ejecutar (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1) en la ventana Inmediato, me sale el mensaje de error y Cannot unbox 'ViewState[TOTAL_RECORD_COUNT] ?? -1' as a 'long' si ejecuto (ViewState[TOTAL_RECORD_COUNT] ?? -1).GetType().Name consigo Int32. Puedo ejecutar (long)-1 y terminar con -1 como un Int64 ... ¿y qué pasa?

¿Fue útil?

Solución

El tipo de retorno del indexador ViewState es Object (supongo que te refieres ASP.NET estado de vista aquí). Ahora considere lo que el compilador tiene que hacer cuando se ve esto (lo que equivale a su código):

object o = ViewState[...];
var x = o ?? -1;

Tiene para deducir el tipo de resultado de o ?? -1 expresión de alguna manera. A la izquierda se ve una object, a la derecha es un int. Claramente, el tipo más general de este término también es object. Sin embargo, esto significa que si en realidad termina usando ese -1 (porque o era nulo), se tendrá que convertirlo a object -. Y por un int, esto significa que el boxeo

Así x es de tipo object, y que puede contener un int (y tal vez también algún otro tipo integral - que no sabemos lo que está en su estado de vista, se podría short, por ejemplo). Ahora se escribe:

long y = (long)x;

Desde x es object, esto es unboxing. Sin embargo, sólo podrá tipos de valor en Unbox mismo tipo exacto (con la única excepción de que se puede sustituir un tipo firmado para un tipo sin signo equivalente y enumeración de su tipo base subyacente). Es decir, no se puede int unbox en long. Una manera mucho más simple de repro de esto, sin código "extra", sería la siguiente:

object x = 123;
long y = (long)x;

Lo que también lanza InvalidCastException, y por exactamente la misma razón.

Otros consejos

Un molde tiene que ser sólo un paso.

El <object> ?? <int> expresión producirá otro objeto, y cuando el primer valor es nulo, es decir. ViewState[TOTAL_RECORD_COUNT] es nulo, entonces el valor resultante será un objeto, con un Int32 en caja en el mismo.

Como no se puede desempacar un objeto que contiene un Int32 a una larga, es necesario desempacar primero a un Int32, y luego convertirlo a un largo.

Los problemas no es el unboxing de la ViewState[TOTAL_RECORD_COUNT], el problema es el boxeo y unboxing de la -1.

   ViewState[TOTAL_RECORD_COUNT] ?? -1

Está utilizando el ?? operador en "objeto" y "int". El tipo resultante es "objeto". Esto significa que el -1 se embalarán (como int) cuando el campo no existe en el estado de vista.

A continuación, el programa se bloquea después, cuando se trata de desempacar el (int) -1 como mucho.

En el original, si se rompe hacia abajo, que estaba haciendo:

(ViewState[TOTAL_RECORD_COUNT] ?? -1)

El null-coalescente operador (??) es specifially diseñado para:

  

para definir un valor predeterminado para un tipo valor anulable así como tipos de referencia.

En su caso, se está usando para manejar un System.Object, así que va a tomar su "-1", lo tratan como un Int32, y la caja en un nuevo System.Object. Entonces, se trata de desempacar el Int32 en una larga, lo que falla, ya que el yeso no puede desempacar y cambiar el tipo en un solo paso.

Puede resolver esto fácilmente especificando que su -1 es mucho utilizando el sufijo L:

public long TotalRecordCount
{
    get { return (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1L); }
    set { ViewState[TOTAL_RECORD_COUNT] = value; }
}

Int64 es un tipo de valor, por lo que la fundición null a un tipo de valor siempre será una excepción (NullReferenceException). Y emitan un Int32 Int64 que tendrá éxito y no lanzar una InvalidCastException.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top