2010-06-09 9 views
7

¿Alguien puede arrojar luz sobre por qué la contravariancia no funciona con los tipos de valores C#?Delegados contravariantes Tipos de valor

La continuación no funciona

private delegate Asset AssetDelegate(int m); 

internal string DoMe() 
{ 
    AssetDelegate aw = new AssetDelegate(DelegateMethod); 
    aw(32); 
    return "Class1"; 
} 

private static House DelegateMethod(object m) 
{ 
    return null; 
} 
+1

Me gustaría publicar una respuesta, pero no quiero perder el tiempo con la redacción. Consulte la entrada del blog de Eric Lippert aquí, específicamente los comentarios. http://blogs.msdn.com/b/ericlippert/archive/2007/10/19/covariance-and-contravariance-in-c-part-three-member-group-conversion-variance.aspx Parece ser una caso de "valores" de tipo de referencia que tienen la misma huella de memoria, que no es el caso para los tipos de valores. Dicho esto, el DelgateMethod podría hacerse genérico, que luego admitiría ints, longs, etc. –

Respuesta

5

El problema es que int no es un objeto.

Un int puede ser en caja a un objeto. El objeto resultante (también conocido como boxed int) es, por supuesto, un objeto, pero ya no es exactamente un int.

Tenga en cuenta que el "es" Estoy utilizando anteriormente no es lo mismo que el operador C# is. Mi "es" significa "es convertible por conversión de referencia implícita". Este es el significado de "es" utilizado cuando hablamos de covarianza y contravarianza.

Un int es implícitamente convertible a un objeto, pero esto no es una conversión de referencia. Tiene que estar en caja.

Un House es implícitamente convertible a Asset a través de una conversión de referencia. No es necesario crear o modificar ningún objeto.

Considere el siguiente ejemplo. Ambas variables house y asset hacen referencia al mismo objeto. Las variables integer y boxedInt, por otro lado, tienen el mismo valor, pero hacen referencia a cosas diferentes.

House house = new House(); 
Asset asset = house; 

int integer = 42; 
object boxedInt = integer; 

Boxing and Unboxing no es tan simple como podría parecer. Tiene muchas sutilezas y podría afectar tu código de formas inesperadas. Mezclar boxeo con covarianza y contravarianza es una manera fácil de deslumbrar a cualquiera.

+0

En mi opinión, intentar pretender que los tipos de valores derivan de 'System.Object' no es útil. Es mucho más útil reconocer que para cada tipo de valor hay un tipo de clase "encajonado" asociado que deriva de 'System.ValueType'. Los tipos de valores son implícitamente convertibles a sus equivalentes de tipo de clase, y se puede usar un molde explícito para copiar el contenido de un tipo de valor enmarcado a uno real. – supercat

1

Estoy de acuerdo con el comentario de Anthony Pegram - que se basa en los tipos de referencia que tienen una huella de memoria diferente que los tipos de valores: el CLR puede utilizar de forma implícita una clase de un tipo como una clase de su tipo súper, pero cuando empiece a usar tipos de valores, el CLR deberá insertar su número entero para que funcione en el lugar del objeto.

Si usted está buscando para hacer que funcione de todos modos, tengo una tendencia a envolver la declaración en una expresión:

AssetDelegate aw = new AssetDelegate((m) => DelegateMethod(m)); 

No sé si eso es bueno o no la práctica en lo que va de sintaxis , pero recuerda que el boxeo y el desembalaje son caros.

Cuestiones relacionadas