2008-12-11 11 views
20

Al usar la palabra clave 'como' en C# para hacer una conversión que falla, se devuelve nulo. ¿Qué está pasando en el fondo? ¿Simplemente está suprimiendo una excepción, así que no tengo que escribir el código de manejo para una falla?Implicaciones de rendimiento de conversión C#

Me interesan las características de rendimiento en comparación con un modelo típico envuelto en un try-catch.

Respuesta

49

Está utilizando la instrucción IL isinst para realizar el reparto en lugar de la instrucción castclass que se utiliza al lanzar. Esta es una instrucción especial que realiza el lanzamiento si es válido, de lo contrario deja null en la pila si no lo está. Así que no, no solo suprime una excepción, y es órdenes de magnitud más rápido que hacerlo.

Tenga en cuenta que hay algunas diferencias de comportamiento entre la instrucción y isinstcastclass - la principal es que isinst no tiene en cuenta los operadores de conversión definidos por el usuario, sólo considera jerarquía de herencia directa, por ejemplo, si se definen los siguientes dos clases sin jerarquía de herencia, sino un operador de conversión explícita:

class A 
{ 
    public int Foo; 
} 

class B 
{ 
    public int Foo; 

    public static explicit operator B(A a) 
    { 
     return new B { Foo = a.Foo }; 
    } 
} 

A continuación, el siguiente tendrá éxito:

var a = new A { Foo = 3 }; 
var b = (B)a; 
Console.WriteLine(b.Foo); // prints 3 

Sin embargo, el siguiente no se compila, con el error 'No se puede convertir tipo 'a' a 'B' a través de una conversión de referencia, la conversión de boxeo, la conversión unboxing, la conversión de envolver, o la conversión de tipo nulo'

var a = new A { Foo = 3 }; 
var b = a as B; 

Así que si usted tiene una y la configuración de conversiones definida por el usuario (que normalmente es una mala idea para los tipos de referencia, por esta razón y otras), entonces debe tener en cuenta esta diferencia.

+0

¿Cuál es el motivo por el que no se compilará? Pensé que el 'como' solo se evalúa después de la ejecución del código. ¿Eso significa que el compilador también verifica el envío durante el tiempo de compilación? – faulty

+0

@faulty - El compilador verificará estáticamente las conversiones siempre que sea posible para asegurarse de que no está escribiendo código que posiblemente no tenga éxito (no recuerdo si esto fue una advertencia o un error, ya que siempre tengo advertencias cuando los errores se activan) –

7

Y para agregar a excelente post de Greg ...

La primera vez que se hace referencia a un nuevo tipo en tiempo de ejecución, las cargas de CLR en la memoria una estructura llamada COREINFO_CLASS_STRUCT (o algo similar) que contiene, entre otras cosas, un puntero al objeto COREINFO_CLASS_STRUCT para la clase base de la que se deriva este objeto ... Esto crea efectivamente una lista vinculada de COREINFO_CLASS_STRUCT objetos para la cadena de herencia para el Tipo, que termina en COREINFO_CLASS_STRUCT para System.Object. Cuando ejecuta isinst, (o su método análogo es castclass) simplemente tiene que encontrar la estructura de memoria COREINFO_CLASS_STRUCT para el tipo concreto del objeto que está examinando, y recorrer esta lista vinculada para ver si el Tipo al que está tratando de convertir está en la lista.

También contiene un puntero a una matriz separada que contiene todas las interfaces implementadas por el Tipo, que se deben buscar por separado si se intenta convertir a una interfaz.

Cuestiones relacionadas