Кажется, что объект 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>
Конечно, вы можете сделать это, вытащив все из списка строк и поместив его обратно по одному, но это довольно запутанное решение.
Подумайте об этом так, если вы выполняете такое приведение, а затем добавляете объект типа 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>
. Причина в том, что обобщенный класс like List<>
в большинстве случаев рассматривается как обычный класс. например, когда вы говорите, List<string>()
что компилятор говорит ListString()
(который содержит строки). [Технический фолк: это очень простая и понятная версия того, что происходит]
Следовательно, очевидно, что компилятор не может быть достаточно умным, чтобы преобразовать ListString в ListObject путем приведения элементов его внутренней коллекции.
Вот почему есть методы расширения для IEnumerable, такие как Convert (), которые позволяют легко предоставлять преобразование для элементов, хранящихся в коллекции, что может быть так же просто, как приведение к одному.
Майк - я считаю, что контравариантность не разрешена в C #
Посмотрите Универсальный параметр параметра дисперсии в CLR для получения дополнительной информации.
Это во многом связано с ковариацией, например, универсальные типы рассматриваются как параметры, и если параметры не разрешаются должным образом для более конкретного типа, то операция завершается неудачей. Смысл этого в том, что вы действительно не можете привести к более общему типу, подобному объекту. И, как утверждает Рекс, объект 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, взгляните на метод 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<object>
может показаться разрешающим) - потому что тогда ваш код потерпит крах (потому что список действительно есть List<string>
и будет принимать только объекты типа String ). Вот почему вы не можете привести свою переменную к более общей спецификации.
В Java все наоборот, у вас нет универсальных шаблонов, и вместо этого все является списком объектов во время выполнения, и вы действительно можете вставить любой странный объект в свой предположительно строго типизированный список. Ищите «Reified generics», чтобы увидеть более широкое обсуждение проблемы Java ...
Такая ковариация в дженериках не поддерживается, но вы можете сделать это с массивами:
object[] a = new string[] {"spam", "eggs"};
C # выполняет проверки во время выполнения, чтобы помешать вам, скажем, поместить int
в a
.
Да, вы можете из .NET 3.5:
List<string> sl = new List<string>();
List<object> ol = sl.Cast<object>().ToList();
Я думаю, что это (противоположность) будет фактически поддерживаться в C # 4.0. http://blogs.msdn.com/charlie/archive/2008/10/27/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx
Вот еще одно решение до .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>
что, наконец, сработало для меня, было вот этим:
Leerlingen = (List<Leerling>)_DeserialiseerLeerlingen._TeSerialiserenObjecten.Cast<Leerling>();
.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);