2009-02-05 24 views
12

Dadas las siguientes definiciones de clases:Copiar una lista <BaseClass> a la lista <DerivedClass>

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

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

¿Cómo puede tomar un List<BaseClass> I y convertirlo en un List<DerivedClass>?

En mi escenario real, BaseClass tiene un montón de propiedades que no quiero copiar una a una (y luego recordar mantenerlas si se agrega una propiedad adicional).

Agregar un constructor con parámetros a BaseClass no es una opción ya que esta clase está definida por una referencia de servicio WCF.

+0

¿WCF no genera las clases _partial_ en el código proxy? –

+0

En otro vistazo, no dijo si DerivedClass es solo una extensión funcional en la parte superior de la base o si realmente tiene que ser una estructura de datos diferente como lo sugiere la muestra del código. En mi humilde opinión, en el segundo caso, "conversión" no tiene sentido. –

Respuesta

13
List<DerivedClass> result = 
    listBaseClass.ConvertAll(instance => (DerivedClass)instance); 

En realidad ConvertAll es bueno cuando se necesita para crear nuevos objetos basado en el original, cuando sólo se necesita para echar puede utilizar el siguiente

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

Si no todos los elementos de la lista puede convertirse a continuación, utilizar DerivedClass OfType lugar

List<DerivedClass> result = 
    listBaseClass.OfType<DerivedClass>().ToList(); 
+0

Me arrepentiré de tentarlo aquí, ¿verdad? ;) –

+0

Lo aprendí de tu libro :-) –

+0

Eso no parece funcionar ... –

15

no se puede convertir el objeto real, pero es fácil de crear una nueva lista con los contenidos convertidos:

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

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

O si usted no está usando C# 3:

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

Esto supone que la lista original era en realidad llena de ejemplos de DerivedClass. Si ese no es el caso, cambie el delegado para crear una instancia apropiada de DerivedClass basada en la BaseClass dada.

EDIT: No estoy seguro de por qué no acaba de publicar una solución LINQ:

List<DerivedClass> derivedList = baseList.Cast<DerivedClass>().ToList(); 
+0

Esto no parece funcionar. Creo que es porque no se puede convertir desde una clase base a una clase derivada. –

+0

@DanBailiff: Como se indica en la respuesta: "Esto supone que la lista original en realidad estaba llena de instancias de DerivedClass". En ese caso, * does * work. Si crees que no es así, deberás dar más detalles. –

+0

@Jon Creo que usted es el rey indiscutible de C# –

3

(repetida de here)

En primer lugar - en cuenta que puede añadir constructores (y otro código) a las clases de WCF: solo tienes que hacerlo en una clase parcial (y dejar solo el código generado).

suena como el tipo de los elementos de la lista que haya que cambiar - por lo que no se puede simplemente fundido. La reflexión es una opción, pero es lenta. Dado que está utilizando 3.5, tal vez podamos escribir un Expression que lo haga por nosotros de manera más eficiente a lo largo de ... these lines, pero el uso de la segunda clase también:

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
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; } 
    } 

} 

Este código no sólo vamos a convertir, pero también solo incluyen instancias que SON la clase derivada y excluyen las que no lo son.

2

Como otros han sugerido, si usted tiene una instancia de un List<BaseClass> se puede convertir a un List<DerivedClass> utilizando el método de ListConvertAll.

De manera más general, si tiene algo que implementa IEnumerable<T> (que no tiene un método ConvertAll) se puede utilizar LINQ de Cast a hacer lo mismo:

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

Si necesita un un List atrás en vez de un IEnumerable, simplemente puede marcar una llamada al ToList() al final.

Como dijo Jon, sin embargo, eso es todo suponiendo que todas las entradas en listBaseClass son realmente del tipo DerivedClass.

Cuestiones relacionadas