Почему я не могу назначить List <int>для IEnumerable <object>в .NET 4.0 - PullRequest
11 голосов
/ 18 ноября 2011

Я пытаюсь сделать это:

IEnumerable<object> ids = new List<string>() { "0001", "0002", "0003" };

это прекрасно работает!

Но когда я пытаюсь сделать это:

IEnumerable<object> intIds = new List<System.Int32>() { 1, 2, 3 };

Visual Studio говорит мне:Не удается неявно преобразовать тип 'System.Collections.Generic.List' в 'System.Collections.Generic.IEnumerable'.Существует явное преобразование (вам не хватает приведения?)

Почему это так?

Ответы [ 4 ]

6 голосов
/ 18 ноября 2011

Проще говоря: универсальная дисперсия в .NET 4 не поддерживает дисперсию для аргументов типа, являющихся типами значений.

Причина, по которой это может работать для ссылочных типов, заключается в том, что, как только CLR решит, что он знает универсальныепреобразование безопасно, оно может обрабатывать все ссылочные значения одинаково - они имеют одинаковое представление внутри.Не требуется фактическое преобразование, чтобы превратить string ссылку в object ссылку, или наоборот, если вы знаете, что это определенно ссылка на строку - это в основном те же самые биты.Таким образом, сгенерированный нативный код может просто обращаться со ссылками как с ссылками, радуясь тому, что правила, связанные с дисперсией, гарантируют, что на уровне безопасности типов ничего не произойдет, и не выполняют никаких преобразований для самих значений.

То, что не истина для типов значений, или для ссылочных типов, где преобразование не является "ссылочным преобразованием" (т. Е. Сохраняющим представление).Вот почему вы не можете написать IEnumerable<XName> names = new List<string>(); кстати ...

5 голосов
/ 18 ноября 2011

int является типом значения и может быть помещен только в object - он не наследуется от object.Так как вы все равно используете IEnumerable<object>, это должно работать:

IEnumerable intIds = new List<int>() { 1, 2, 3 };
4 голосов
/ 18 ноября 2011

Из Блоги MSDN> Часто задаваемые вопросы по C #> Часто задаваемые вопросы по ковариации и контравариантности :

Дисперсия поддерживается, только если параметр типа является ссылочным типом. Дисперсия не поддерживается для типов значений. Следующее также не компилируется:

// int is a value type, so the code doesn't compile.
IEnumerable<Object> objects = new List<int>(); // Compiler error here.
0 голосов
/ 03 июля 2014

Другим решением будет использование метода расширения Enumerable.Cast как такового:

Dim a as IEnumerable(Of Integer) = GetA()

MethodThatTakesIEnumerableOfObject(a.Cast(Of Object))
...