Подтвердить что ты не робот

Копирование списка <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.

4b9b3361

Ответ 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.