Почему явное преобразование List <double> в IEnumerable <object> вызывает исключение?

В соответствии с этим ссылка MSDN IEnumerable является ковариантной, и это позволяет неявно списывать список объектов на перечисляемый:

IEnumerable<String> strings = new List<String>();
IEnumerable<Object> objects = strings;

В моем собственном коде я написал строку кода, которая отлично работает, когда тип элемента списка является классом Point (Point - это простой класс с тремя свойствами double x, y, z):

var objects = (IEnumerable<object>)dataModel.Value;
// here property Value is a list that could be of any type. 

Но приведенный выше код возвращает следующее исключение, если тип элемента списка double:

Unable to cast object of type System.Collections.Generic.List1[System.Double] 
to type System.Collections.Generic.IEnumerable1[System.Object].

В чем разница между string и double и чем заставляет код работать с string, но не с double?

Update

В соответствии с этим сообщением мы просто можем перечислить список IEnumerable (без аргумента типа), так как мне нужно только перебирать элементы и добавлять новые элементы в список (на самом деле мне вообще не нужно бросать элементы списка). Я решил использовать этот:

var objects = (IEnumerable)dataModel.Value;

Но если вам нужно наложить элементы списка на object и использовать их, ответ от Theodoros - это решение, которое вы больше всего следуете.

Ответы

Ответ 1

Построенные типы вариантов интерфейсов (например, IEnumerable<out T>) являются вариантами только для аргументов ссылочного типа, потому что их неявное преобразование в супертип (например, object) является преобразованием, не изменяющим представление. Вот почему IEnumerable<string> является ковариантным.

Построенные типы для аргументов типа значения являются инвариантными, потому что их неявное преобразование в супертип (например, object) является изменением представления из-за бокса, который требовал. Вот почему IEnumerable<double> является инвариантным.

Смотрите соответствующую документацию:

Отклонение применяется только к ссылочным типам; если вы укажете тип значения для параметра типа варианта, этот тип параметра является инвариантным для результирующего построенного типа.

Возможным обходным путем является использование LINQ cast:

var sequence = list.Cast<object>();

Сначала проверьте, соответствует ли источник совместимости с IEnumerable<TResult>, с которой вы пытаетесь передать его.