¿Por qué no se permite la última línea?
Porque el doble es un tipo de valor y el objeto es un tipo de referencia; la covarianza solo funciona cuando ambos tipos son tipos de referencia.
¿Esto se debe a que el doble es un tipo de valor que no se deriva del objeto, por lo tanto, la covarianza no funciona?
No. Double does derive from object. Todos los tipos de valores se derivan del objeto.
Ahora la pregunta que debería haber preguntado:
¿Por qué no funciona covarianza para convertir IEnumerable<double>
a IEnumerable<object>
?
Porque que hace el boxeo? Una conversión de doble a objeto debe box el doble. Supongamos que tiene una llamada al IEnumerator<object>.Current
que es "realmente" una llamada a una implementación de IEnumerator<double>.Current
. La persona que llama espera que se devuelva un objeto. El destinatario devuelve un doble. ¿Dónde está el código que hace la instrucción de boxeo que convierte el doble devuelto por IEnumerator<double>.Current
en un doble en caja?
Es en ninguna parte, ahí es donde, y es por eso que esta conversión es ilegal. La llamada al Current
va a poner un doble de ocho bytes en la pila de evaluación, y el consumidor va a esperar una referencia de cuatro bytes a un doble en la pila de evaluación, por lo que el consumidor se bloqueará y morirá horriblemente con una pila desalineada y una referencia a la memoria no válida.
Si desea que el código que se ejecutará cajas a entonces tiene que haber escrito en algún momento, y usted es la persona que recibe a escribirlo. La forma más sencilla es utilizar el método Cast<T>
extensión:
IEnumerable<object> objects2 = doubleenumerable.Cast<object>();
Ahora se llama a un método de ayuda que contiene la instrucción de boxeo que convierte el doble de una de ocho bytes doble a una referencia.
ACTUALIZACIÓN: Un comentarista nota que he planteado la pregunta, es decir, he respondido una pregunta presuponiendo la existencia de un mecanismo que resuelve un problema tan difícil como lo requiere una solución a la pregunta original. ¿Cómo se logra la implementación de Cast<T>
para resolver el problema de saber si boxear o no?
Funciona como este boceto. Tenga en cuenta que los tipos de parámetros son no genérico:
public static IEnumerable<T> Cast<T>(this IEnumerable sequence)
{
if (sequence == null) throw ...
if (sequence is IEnumerable<T>)
return sequence as IEnumerable<T>;
return ReallyCast<T>(sequence);
}
private static IEnumerable<T> ReallyCast<T>(IEnumerable sequence)
{
foreach(object item in sequence)
yield return (T)item;
}
La responsabilidad de determinar si el reparto de un objeto a T es una conversión unboxing o una conversión de referencia se difiere al tiempo de ejecución. La fluctuación de fase sabe si T es un tipo de referencia o un tipo de valor. El 99% del tiempo será, por supuesto, un tipo de referencia.
posible duplicado de [Por qué la covarianza y la contravarianza no admiten el tipo de valor] (http://stackoverflow.com/questions/12454794/why-covariance-and-contravariance-do-not-support-value-type) – nawfal