Кажется, что объект List не может быть сохранен в переменной List в C # и даже не может быть явно приведен таким образом.
List<string> sl = new List<string>();
List<object> ol;
ol = sl;
приводит к невозможности неявно преобразовать тип System.Collections.Generic.List<string>
вSystem.Collections.Generic.List<object>
А потом...
List<string> sl = new List<string>();
List<object> ol;
ol = (List<object>)sl;
приводит к невозможности преобразования типа System.Collections.Generic.List<string>
вSystem.Collections.Generic.List<object>
Конечно, вы можете сделать это, вытащив все из списка строк и вставив обратно по одной, но это довольно запутанное решение.
c#
.net
generics
covariance
type-safety
Мэтт Шеппард
источник
источник
Ответы:
Подумайте об этом так: если бы вы сделали такое приведение, а затем добавили в список объект типа Foo, список строк больше не согласован. Если бы вы перебрали первую ссылку, вы бы получили исключение приведения класса, потому что после того, как вы нажмете на экземпляр Foo, Foo не может быть преобразовано в строку!
В качестве побочного примечания, я думаю, было бы более важно, сможете ли вы выполнить обратное приведение:
List<object> ol = new List<object>(); List<string> sl; sl = (List<string>)ol;
Я давно не использовал C #, поэтому не знаю, законно ли это, но такой вид приведений на самом деле (потенциально) полезен. В этом случае вы переходите от более общего класса (объекта) к более конкретному классу (строке), который расширяется от общего. Таким образом, если вы добавляете в список строк, вы не нарушаете список объектов.
Кто-нибудь знает или может проверить, допустимо ли такое приведение в C #?
источник
ol
бы в нем было что-то, кроме строки, я бы ожидал, что приведение не удастся во время выполнения. Но где вы действительно столкнетесь с проблемами, так это если приведение выполнено успешно, а затем к нему было добавленоol
что-то, а не строка. Посколькуsl
ссылается на один и тот же объект, теперь вашList<string>
будет содержать не строку. ЭтоAdd
проблема, которая, я думаю, объясняет, почему этот код не компилируется, но он будет компилироваться, если вы измените егоList<object> ol
наIEnumerable<object> ol
, который не имеет файлаAdd
. (Я проверил это на C # 4)InvalidCastException
потому что тип среды выполненияol
остается прежнимList<object>
.Если вы используете .NET 3.5, обратите внимание на метод Enumerable.Cast. Это метод расширения, поэтому вы можете вызывать его прямо в списке.
List<string> sl = new List<string>(); IEnumerable<object> ol; ol = sl.Cast<object>();
Это не совсем то, о чем вы просили, но должно помочь.
Изменить: как отметил Zooba, вы можете затем вызвать ol.ToList (), чтобы получить список
источник
Вы не можете выполнять приведение между универсальными типами с разными параметрами типа. Специализированные универсальные типы не являются частью одного и того же дерева наследования, как и несвязанные типы.
Для этого до NET 3.5:
List<string> sl = new List<string>(); // Add strings to sl List<object> ol = new List<object>(); foreach(string s in sl) { ol.Add((object)s); // The cast is performed implicitly even if omitted }
Используя Linq:
var sl = new List<string>(); // Add strings to sl var ol = new List<object>(sl.Cast<object>()); // OR var ol = sl.Cast<object>().ToList(); // OR (note that the cast to object here is required) var ol = sl.Select(s => (object)s).ToList();
источник
Причина в том, что универсальный класс вроде
List<>
для большинства целей обрабатывается извне как обычный класс. например, когда вы говорите,List<string>()
что компилятор говоритListString()
(который содержит строки). [Технический специалист: это чрезвычайно простая английская версия того, что происходит]Следовательно, очевидно, что компилятор не может быть достаточно умен, чтобы преобразовать ListString в ListObject путем преобразования элементов его внутренней коллекции.
Вот почему существуют методы расширения для IEnumerable, такие как Convert (), которые позволяют легко выполнять преобразование для элементов, хранящихся внутри коллекции, что может быть таким же простым, как преобразование из одного в другой.
источник
Это во многом связано с ковариацией, например, общие типы рассматриваются как параметры, и если параметры не разрешаются должным образом в более конкретный тип, операция завершается ошибкой. Следствием этого является то, что вы действительно не можете привести к более общему типу, например объекту. И, как заявил Рекс, объект List не будет преобразовывать каждый объект за вас.
Вместо этого вы можете попробовать код ff:
List<string> sl = new List<string>(); //populate sl List<object> ol = new List<object>(sl);
или:
List<object> ol = new List<object>(); ol.AddRange(sl);
ol (теоретически) скопирует все содержимое sl без проблем.
источник
Да, из .NET 3.5 можно:
List<string> sl = new List<string>(); List<object> ol = sl.Cast<object>().ToList();
источник
Майк - я считаю, что контравариантность также недопустима в C #
Дополнительные сведения см. В разделе « Вариативность параметра универсального типа» в среде CLR .
источник
Я думаю, что это (контравариантность) действительно будет поддерживаться в C # 4.0. http://blogs.msdn.com/charlie/archive/2008/10/27/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx
источник
Это на самом деле для того, чтобы вы не пытались поместить какой-либо нечетный «объект» в свой вариант списка «ol» (
List<object>
что, казалось бы, допускает) - потому что тогда ваш код выйдет из строя (поскольку список действительно естьList<string>
и будет принимать только объекты типа String ). Вот почему вы не можете привести переменную к более общей спецификации.На Java все наоборот, у вас нет универсальных шаблонов, и вместо этого все является списком объектов во время выполнения, и вы действительно можете поместить любой странный объект в свой предположительно строго типизированный список. Найдите "Reified generics", чтобы увидеть более подробное обсуждение проблемы Java ...
источник
Такая ковариация для дженериков не поддерживается, но вы можете сделать это с помощью массивов:
object[] a = new string[] {"spam", "eggs"};
C # выполняет проверки во время выполнения, чтобы вы не поместили, скажем,
int
вa
.источник
Вот еще одно решение до .NET 3.5 для любого списка IList, содержимое которого может быть неявно приведено.
public IList<B> ConvertIList<D, B>(IList<D> list) where D : B { List<B> newList = new List<B>(); foreach (D item in list) { newList.Add(item); } return newList; }
(На примере Zooba)
источник
У меня есть:
private List<Leerling> Leerlingen = new List<Leerling>();
И я собирался заполнить его данными, собранными в.
List<object>
Что, наконец, сработало для меня:.Cast
это типа вы хотите получитьIEnumerable
от этого типа, то напечатанныйIEnemuerable
кList<>
вы хотите.источник
Мм, благодаря предыдущим комментариям я нашел два способа выяснить это. Первый - это получение строкового списка элементов и преобразование его в список объектов IEnumerable:
IEnumerable<object> ob; List<string> st = new List<string>(); ob = st.Cast<object>();
И второй - избегает объектного типа IEnumerable, просто преобразуя строку в объектный тип, а затем используя функцию «toList ()» в том же предложении:
List<string> st = new List<string>(); List<object> ob = st.Cast<object>().ToList();
Мне больше нравится второй способ. Надеюсь, это поможет.
источник
List<string> sl = new List<string>(); List<object> ol; ol = new List<object>(sl);
источник