2010-02-16 10 views
7

Estoy seguro de que me falta algo simple, sin embargo, estoy tratando de convertir una lista fuertemente tipada de objetos que implementan una interfaz en una lista de ese tipo de interfaz .Cómo convertir una lista genérica <T> en una lista basada en interfaz <T>

A continuación se muestra un ejemplo para demostrar el error:

public void ExampleCode(){ 
    List<Cube> cubes = new List<Cube>(); 
    List<Shape> allShapes; 
    allShapes = cubes;//Syntax Error 
    allShapes = (List<Shape>)cubes;//Syntax Error 
} 

public class Cube : Shape 
{ 
    public int ID { get; set; } 
    public int Sides { get; set; } 
} 

public interface Shape 
{ 
    int ID { get; set; } 
    int Sides { get; set; } 
} 
+0

NB: El código en la pregunta se formula como un molde (es decir, vista diferente del mismo objeto). Las diferentes soluciones dadas a continuación copian la lista: se crea una nueva lista y cada elemento de Forma se agrega a la nueva lista, dando un objeto diferente, no una vista diferente en el mismo objeto. –

Respuesta

13

En lugar de moldear así, tratar:

allShapes = cubes.Cast<Shape>().ToList(); 

Usted necesita .NET 3.5 para esto. Creo que el método de extensión de Cast se puede encontrar en System.Linq.

+1

Me ganaste. – Steven

+2

Nota, esto copia la lista (aunque si contiene referencias a las referencias y no se copiarán los objetos). Esto no es lo mismo que lanzar el objeto de lista en sí mismo. – Richard

+1

@Richard: Gran punto. –

6

No puede. Porque List<T> y ILIst<T> solo admiten parámetros de tipo invariante. Esto se ha reducido a T siendo ambos usados ​​para parámetros de entrada y salida (por ejemplo, valores de retorno). De lo contrario, puede romper el tipo de seguridad.

Otras interfaces (por ejemplo, IEntumerable<T>) permiten algunas variaciones.

Vea el blog de Eric Lippert "Fabulous Adventures In Coding" para la discusión de contra y co-varianza. Específicamente, la etiqueta "Covariance and Contravariance".

Editar, se agregó a la "C# Preguntas más frecuentes" blog: Covariance and Contravariance FAQ

2

No se puede hacer esto ya que por fundición de esta manera que potencialmente puede perder todo tipo de seguridad. Por instinto, la conversión de List<Shape> a List<object> dará como resultado que los objetos de cualquier tipo de se pueden agregar a la lista, lo que será francamente inconsistente.

0

También puede hacer:

allShapes = cubes.ConvertAll(x => (Shape)x); 

O si usted está haciendo esto en .NET 2.0:

allShapes = cubes.ConvertAll<Shape>(delegate(Cube c){ 
    return (Shape)c; 
}); 
4

Lo que se está refiriendo a la que se llama covarianza genérico y no es compatible con C# 3. Es, sin embargo, con el apoyo de C# 4 (.NET 4/VS 2010) y se puede leer más sobre esto aquí:

Variance in Generic Interfaces

Dicho esto, IList<T> no es covariante (porque acepta y expone T). IEnumerable<T>, por otro lado, es covariante (porque no acepta T).

0

Esto funciona si se define como IEnumerable allShapes

En C# 4.0 puede asignar simplemente allshapes = cubos

para C# 3.5 se puede utilizar allShapes = cubos.Seleccione (c => ((Forma) c));

Pero en cualquier caso es necesario utilizar IEnumerable en lugar de Lista

Cuestiones relacionadas