2010-04-30 8 views
7
//always works, returning a valid object into _page 
     _page = _httpContext.Handler as System.Web.UI.Page; 

//Fails throwing the exception : Unable to cast object of type 'System.Web.DefaultHttpHandler' to type 'System.Web.UI.Page' 
     _page = (System.Web.UI.Page)_httpContext.Handler; 

Me gustaría saber por qué sucede esto?¿Por qué funciona la palabra clave 'como' mientras que el molde() no

EDIT:

   //Fixes the problem 
      if(_httpContext.Handler is System.Web.UI.Page) 
      _page = (System.Web.UI.Page)_httpContext.Handler; 

Si i depurar el 'como' declaración de palabras clave, nunca consigo una referencia nula (objeto siempre asignado correctamente). Sin embargo, el molde() crea excepciones a menos que tenga la condición if.

EDITAR: Después de aproximadamente 15 carreras a través de la clase, pude obtener un nulo. Parece que se necesitaron más carreras para encontrar un valor nulo en comparación con la rapidez con la que el reparto() captaría una excepción.

ANTIGUO: Cuando hay una depuración en la instrucción 'como' cada vez que la clase ejecuta los puntos de ruptura, nunca se anula.

Cuando hay una depuración en la instrucción '()' dentro de if, cada vez que el punto de interrupción llega al molde, funciona correctamente. Werid

Respuesta

14

// siempre funciona, devolviendo un objeto válido en _page _page = _httpContext.Handler como System.Web.UI.Page;

Esto no funcionó técnicamente. Si nota _page será null. Simplemente no arrojó un error.

El operador as se usa para indicarle a la aplicación "Quiero que intente convertir esto. Puede que no, y sé esto, por lo tanto, no haga una excepción. Lo resolveré en consecuencia".

La conversión () se usa para decirle a la aplicación: "Este objeto se convertirá en este tipo. Si no algo está mal, y necesito saberlo".

La diferencia entre los dos moldes (y cuándo deberías usarlos) es cuando "piensas" que algo es moldeable a otro tipo y cuando "sabes" que algo se puede moldear a otro tipo.

Aquí es un artículo de Eric Lippert sobre el tema (cambió a su blog no re-alimentado): http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx

0

Si utiliza el operador 'como', si la conversión falla, simplemente devuelve nulo. Si haces un lanzamiento explícito, arrojará una excepción si la conversión falla. En esta situación, se esperan los downcasts 'como' al tipo apropiado. La conversión explícita no puede moverse hasta el tipo deseado.

Como regla general, siempre debe hacer 'como' a menos que realmente necesite la conversión explícita (como cuando necesita convertir a tipos de valores).

+0

No estoy convencido. Preferiría hacer Class1 foo = (Class1) bar y obtener la excepción de conversión que obtener una excepción nula no útil más tarde con foo.Property o foo.Method(). Esa excepción nula podría ocurrir en cualquier lugar fuera del alcance de su "como". Si espero que el código algunas veces falle, usaré "como" y verificará nulo. –

+0

Ese es el patrón general. Convierte con 'como', y luego busca nulo. – Tejs

7

From here:

Usando el operador as difiere de un elenco en C# en tres aspectos importantes:

Devuelve nulo cuando la variable que está intentando convertir no es del tipo solicitado o en su herencia cadena, en lugar de arrojar una excepción . Solo se puede aplicar a las variables de tipo de referencia convirtiendo a tipos de referencia. Usar como no realizar conversiones definidas por el usuario, tales como operadores de conversión implícita o explícita , cuya sintaxis de conversión será do. De hecho, hay dos completamente diferentes operaciones definidas en IL que manejan estas dos palabras clave (la castclass e instrucciones isinst) - no es lo "azúcar sintáctico" escrito por C# para obtener este comportamiento diferente . El operador as parece ser ligeramente más rápido en v1.0 y v1.1 de CLR de Microsoft en comparación con la fundición (incluso en los casos en que no hay moldes inválidas que haría seriamente al rendimiento de fundición más baja debido a excepciones).

+0

¿Pero por qué el yeso no funciona? Sé que Handler es System.Web.UI.Page. También busqué en Google y leí lo que publicaste. Aún así, no sientas ninguna marca. – Mausimo

+0

"Solo se puede aplicar a las variables de tipo de referencia que convierten a los tipos de referencia" no es verdadero, el valor puede ser de cualquier tipo y el tipo de destino también puede ser un tipo de valor que admite valores. Por ejemplo, '(int) 0 como IEtabletable ' es válido, y en particular '(object) o as int?' es una buena forma de comprobar si 'o' es un' int' enmarcado sin capturar excepciones. También le permite escribir cosas como '(T?) X como U?', Que pueden ser marginalmente útiles en el código genérico. –

+3

@Maus en realidad no funciona. La primera línea colocará 'null' en _page que no se parece a lo que esperaba – Earlz

0

Usando as intenta emitir ese objeto para ese tipo específico, pero devuelve null en caso de fallo en lugar de lanzar una excepción (mientras que la colada justo lanza la excepción). ¿Estás seguro de que el que tiene la cláusula as devuelve realmente un objeto no nulo?

+0

Puse una edición, pude encontrar un nulo. – Mausimo

0

Lo mismo que le dijo @Tejs respuesta. Una conversión fallida con as produce null.

Sin embargo, voy a decir diferente de él y como regla general siempre debes usar un lanzamiento explícito. Personalmente, prefería obtener una excepción donde la conversión falla y no en otra página obtener una excepción de referencia nula (aparentemente) de ninguna parte.

Un buen uso para el operador as es, sin embargo, cuando la conversión de las cosas fuera de una base de datos y no querer comprobar System.DBNull

int someint = cmd.ExecuteScalar() as int? ?? 0; 
4

Una diferencia importante entre el como molde y el molde prefijo es que el elenco de prefijo arrojará una excepción mientras que el yeso simplemente arrojará nulo.

0

En realidad, eso es exactamente lo que se supone que debe ocurrir. El lanzamiento falló y arrojó y error porque el lanzamiento no era válido. El as se establece de manera silenciosa en nulo si el lanzamiento falla.

0

Como han notado otras respuestas, se reduce al hecho de que "como" devolverá nulo en el caso de un lanzamiento inválido, mientras que un lanzamiento explícito lanzará una excepción.

Las otras respuestas tienen cierto debate sobre si inclinarse hacia una u otra. Si va a utilizar "como", debe tratar en algún momento con el hecho de que puede ser un nulo. Si vas a utilizar un reparto explícito, debes lidiar con una posible excepción. Dependiendo del caso de uso, me inclino hacia uno u otro.

Tiendo a utilizar el reparto específico cuando sé que el reparto funcionará pero el compilador no, y lanzar una excepción estaría bien (porque es un caso excepcional). Pero si hay una posibilidad legítima de que el elenco no sea válido, prefiero usar "como" y probar nulo. Esto evita capturar la excepción que es más fea y hace que la depuración sea más difícil.

Cuestiones relacionadas