Почему последняя строка не разрешена?
Поскольку double является типом значения, а объект является ссылочным типом;ковариация работает только тогда, когда оба типа являются ссылочными типами.
Это потому, что double - это тип значения, который не является производным от объекта, следовательно, ковариация не работает?
Нет.Двойник происходит от объекта.Все типы значений происходят от объекта.
Теперь вопрос, который вы должны были задать:
Почему ковариация не работает для преобразования IEnumerable<double>
в IEnumerable<object>
?
Потому что кто занимается боксом ?Преобразование из double в объект должно box double.Предположим, у вас есть вызов IEnumerator<object>.Current
, который "действительно" является вызовом реализации IEnumerator<double>.Current
.Вызывающий ожидает, что объект будет возвращен.Колли возвращается дважды. Где находится код, который выполняет инструкцию по боксу, которая превращает двойное число, возвращаемое IEnumerator<double>.Current
в двойное число в штучной упаковке?
Это нигде , это где, и этопочему это обращение незаконно.Вызов Current
приведет к добавлению восьмибайтового двойного числа в стек оценки, и потребитель будет ожидать четырехбайтовую ссылку на вставленный в двойную строку в оценочном стеке, так что потребитель собирается аварийно завершить работу иужасно умри со смещенным стеком и ссылкой на недопустимую память.
Если вы хотите, чтобы код, который помечал , выполнял , то в какой-то момент он должен был быть записан ,и вы тот человек, который хочет это написать.Самый простой способ - использовать метод расширения Cast<T>
:
IEnumerable<object> objects2 = doubleenumerable.Cast<object>();
Теперь вы вызываете вспомогательный метод, содержащий инструкцию бокса, которая преобразует двойное значение из восьмибайтового двойного в ссылку.
ОБНОВЛЕНИЕ: комментатор отмечает, что я задал вопрос - то есть я ответил на вопрос, предполагая существование механизма, который решает проблему так же трудно, как требует решение исходного вопроса.Каким образом реализация Cast<T>
позволяет решить проблему с определением, в коробку или нет?
Это работает как этот скетч.Обратите внимание, что типы параметров не generic:
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;
}
Ответственность за определение того, является ли преобразование из объекта в T преобразованием распаковки или ссылочным преобразованием, переносится на среду выполнения.Джиттер знает, является ли T ссылочным типом или типом значения.В 99% случаев это будет ссылочный тип.