Копирование списка <BaseClass> в список <DerivedClass>
Учитывая следующие определения классов:
public class BaseClass
{
public string SomeProp1 { get; set; }
}
public class DerivedClass : BaseClass
{
public string SomeProp2 { get; set; }
}
Как я могу взять List<BaseClass>
и преобразовать его в List<DerivedClass>
?
В моем реальном сценарии BaseClass
имеется целая куча свойств, которые я не хочу копировать по одному (а затем не забудьте сохранить, добавлено ли дополнительное свойство).
Добавление параметризованного конструктора в BaseClass
не является опцией, так как этот класс определяется ссылкой службы WCF.
Ответы
Ответ 1
List<DerivedClass> result =
listBaseClass.ConvertAll(instance => (DerivedClass)instance);
Фактически ConvertAll хорош, когда вам нужно создавать новые объекты на основе оригинала, когда вам просто нужно бросить, вы можете использовать следующие
List<DerivedClass> result =
listBaseClass.Cast<DerivedClass>();
Если не все элементы в вашем списке могут быть добавлены в DerivedClass, вместо этого используйте OfType
List<DerivedClass> result =
listBaseClass.OfType<DerivedClass>();
Ответ 2
Вы не можете преобразовать фактический объект, но легко создать новый список с преобразованным содержимым:
List<BaseClass> baseList = new List<BaseClass>(...);
// Fill it here...
List<DerivedClass> derivedList = baseList.ConvertAll(b => (DerivedClass) b);
Или, если вы не используете С# 3:
List<DerivedClass> derivedList = baseList.ConvertAll<DerivedClass>(delegate
(BaseClass b) { return (DerivedClass) b; };
Это предполагает, что исходный список был действительно заполнен экземплярами DerivedClass. Если это не так, измените делегат, чтобы создать соответствующий экземпляр DerivedClass на основе данного BaseClass.
EDIT: Я не уверен, почему я не просто опубликовал решение LINQ:
List<DerivedClass> derivedList = baseList.Cast<DerivedClass>().ToList();
Ответ 3
(повторяется от здесь)
Сначала отметим, что вы можете добавлять конструкторы (и другие коды) к классам WCF - вам просто нужно сделать это в частичном классе (и оставить только сгенерированный код).
Похоже, что тип элементов в списке необходимо изменить - поэтому мы не можем просто бросить. Отражение - это вариант, но медленный. Поскольку вы используете 3.5, мы можем написать Expression
, чтобы сделать это для нас более эффективно... по эти строки, но используя второй класс тоже:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
static class Program
{
class Foo
{
public int Value { get; set; }
public override string ToString()
{
return Value.ToString();
}
}
class Bar : Foo {}
static void Main()
{
List<Foo> foos = new List<Foo>();
for (int i = 0; i < 10; i++) foos.Add(new Foo { Value = i });
List<Bar> bars = foos.ConvertAll<Bar>(Clone<Foo, Bar>);
}
public static TTo Clone<TFrom, TTo>(this TFrom obj) where TTo : TFrom, new()
{
return ObjectExtCache<TFrom, TTo>.Convert(obj);
}
static class ObjectExtCache<TFrom, TTo> where TTo : TFrom, new()
{
private static readonly Func<TFrom, TTo> converter;
static ObjectExtCache()
{
ParameterExpression param = Expression.Parameter(typeof(TFrom), "in");
var bindings = from prop in typeof(TFrom).GetProperties()
where prop.CanRead && prop.CanWrite
select (MemberBinding)Expression.Bind(prop,
Expression.Property(param, prop));
converter = Expression.Lambda<Func<TFrom, TTo>>(
Expression.MemberInit(
Expression.New(typeof(TTo)), bindings), param).Compile();
}
public static TTo Convert(TFrom obj)
{
return converter(obj);
}
}
}
Ответ 4
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace ConsoleApplication22
{
class Program
{
static void Main(string[] args)
{
List<BaseClass> source = new List<BaseClass>();
source.Add(new DerivedClass { Name = "One" });
source.Add(new BaseClass());
source.Add(new DerivedClass { Name = "Three" });
List<DerivedClass> result =
new List<DerivedClass>(source.OfType<DerivedClass>());
result.ForEach(i => Console.WriteLine(i.Name));
Console.ReadLine();
}
}
public class BaseClass
{
}
public class DerivedClass : BaseClass
{
public string Name { get; set; }
}
}
Этот код будет не только преобразовывать, но также включать только экземпляры, которые являются производным классом и исключают любые, которые не являются.
Ответ 5
Как показали другие, если у вас есть экземпляр List<BaseClass>
, вы можете преобразовать его в List<DerivedClass>
с помощью метода ConvertAll
List
.
В общем случае, если у вас есть что-либо, что реализует IEnumerable<T>
(у которого нет метода ConvertAll
), вы можете использовать Linq Cast
для выполнения той же самой вещи:
IEnumerable<DerivedClass> result = listBaseClass.Cast<DerivedClass>();
Если вам нужна a List
, а не IEnumerable
, вы можете просто сделать вызов ToList()
в конце.
Так как Джон сказал, что все предполагают, что все записи в listBaseClass
действительно имеют тип DerivedClass
.