Копирование списка <BaseClass>в список <DerivedClass> - PullRequest
22 голосов
/ 05 февраля 2009

Учитывая следующие определения классов:

public class BaseClass
{
    public string SomeProp1 { get; set; }
}

public class DerivedClass : BaseClass
{
    public string SomeProp2 { get; set; }
}

Как я могу взять List<BaseClass> и преобразовать его в List<DerivedClass>?

В моем реальном сценарии BaseClass имеет целую кучу свойств, которые мне не нужно копировать по одному (и затем не забывайте сохранять, если добавляется дополнительное свойство).

Добавление параметризованного конструктора в BaseClass не вариант, так как этот класс определяется ссылкой на службу WCF.

Ответы [ 6 ]

23 голосов
/ 05 февраля 2009
List<DerivedClass> result = 
    listBaseClass.ConvertAll(instance => (DerivedClass)instance);

На самом деле ConvertAll хорош, когда вам нужно создавать новые объекты на основе оригинала, когда вам просто нужно наложить, вы можете использовать следующее

List<DerivedClass> result = 
    listBaseClass.Cast<DerivedClass>().ToList();

Если не все элементы в вашем списке могут быть преобразованы в DerivedClass, вместо этого используйте OfType

List<DerivedClass> result =
    listBaseClass.OfType<DerivedClass>().ToList();
17 голосов
/ 05 февраля 2009

Вы не можете преобразовать реальный объект, но легко создать новый список с преобразованным содержимым:

List<BaseClass> baseList = new List<BaseClass>(...);
// Fill it here...

List<DerivedClass> derivedList = baseList.ConvertAll(b => (DerivedClass) b);

Или, если вы не используете C # 3:

List<DerivedClass> derivedList = baseList.ConvertAll<DerivedClass>(delegate
    (BaseClass b) { return (DerivedClass) b; };

Предполагается, что исходный список на самом деле был полон экземпляров DerivedClass. Если это не так, измените делегат, чтобы создать соответствующий экземпляр DerivedClass на основе заданного BaseClass.

РЕДАКТИРОВАТЬ: я не уверен, почему я не просто опубликовал решение LINQ:

List<DerivedClass> derivedList = baseList.Cast<DerivedClass>().ToList();
3 голосов
/ 05 февраля 2009

(повторяется от здесь )

Первое - обратите внимание, что вы можете добавить конструкторы (и другой код) к классам 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);
        }
    }
}
2 голосов
/ 05 февраля 2009

Как уже предлагали другие, если у вас есть экземпляр List<BaseClass>, вы можете преобразовать его в List<DerivedClass>, используя метод ConvertAll из List.

В более общем смысле, если у вас есть что-то, что реализует IEnumerable<T> (у которого нет метода ConvertAll), вы можете использовать Cast Linq, чтобы сделать то же самое:

IEnumerable<DerivedClass> result = listBaseClass.Cast<DerivedClass>();

Если вам нужен List назад вместо IEnumerable, вы можете просто поставить вызов на ToList() на конце.

Однако, как сказал Джон, все это предполагает, что все записи в listBaseClass на самом деле имеют тип DerivedClass.

2 голосов
/ 05 февраля 2009
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; }
    }

}

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

0 голосов
/ 17 сентября 2018

Только для записи, если есть конструктор с параметрами, вам нужно явно создать экземпляр каждого элемента в списке.

Используя пример OP:

public class BaseClass
{
    public BaseClass (string param1)
    {
         Param1 = param1;
    }
    public string SomeProp1 { get; set; }
    public string Param1 { get; private set; }
}

public class DerivedClass : BaseClass
{
    public DerivedClass (string param1) : base(param1){}
    public string SomeProp2 { get; set; }
}

В этом случае строка кода должна выглядеть примерно так:

List<DerivedClass> result = listBaseClass.ConvertAll(l=> new DerivedClass(l.Param1));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...