Pregunta

Tengo una interfaz definida de la siguiente manera:

public interface TestInterface{
    int id { get; set; }
}

Y dos Linq to SQL clases que implementan la interfaz:

public class tblTestA : TestInterface{
    public int id { get; set; }
}

public class tblTestB : TestInterface{
    public int id { get; set; }
}

He IEnumerable las listas a y b poblada por los registros de base de datos de tblTestA y tblTestB

IEnumerable<tblTestA> a = db.tblTestAs.AsEnumerable();
IEnumerable<tblTestB> b = db.tblTestBs.AsEnumerable();

Sin embargo, el siguiente no está permitido:

List<TestInterface> list = new List<TestInterface>();
list.AddRange(a);
list.AddRange(b);

Que tengo que hacer lo siguiente:

foreach(tblTestA item in a)
    list.Add(item)

foreach(tblTestB item in b)
    list.Add(item)

Hay algo que estoy haciendo mal?Gracias por la ayuda

¿Fue útil?

Solución

Esto funciona en C# 4, debido a genérico covarianza.A diferencia de versiones anteriores de C#, hay una conversión de IEnumerable<tblTestA> a IEnumerable<TestInterface>.

La funcionalidad ha sido en el CLR de la v2, pero sólo se ha expuesto en C# 4 (y en el marco de los tipos de no tomar ventaja de ello antes de .NET 4 o).Es sólo se aplica a los delegados e interfaces genéricos (no clases) y sólo para los tipos de referencia (por lo que no hay conversión de IEnumerable<int> a IEnumerable<object> por ejemplo.) También sólo funciona cuando tiene sentido - IEnumerable<T> es covariante como objetos sólo vienen de "fuera" de la API, mientras que IList<T> es invariantes debido a que usted puede agregar valores con que API.

Genérico contravarianza también es compatible con el trabajo en la otra dirección - así, por ejemplo, usted puede convertir de IComparer<object> a IComparer<string>.

Si no estás usando C# 4, luego de Tim sugerencia de uso Enumerable.Cast<T> es un buen uno se pierde un poco la eficiencia, sino que va a trabajar.

Si usted desea aprender más acerca de la variación genérica, Eric Lippert tiene un larga serie de entradas de blog sobre ello, y me dio una charla sobre esto en NDC de 2010, el cual se puede ver en la NDC de la página de vídeo.

Otros consejos

No estás haciendo nada mal: List<TestInterface>.AddRange espera un IEnumerable<TestInterface>.No aceptar una IEnumerable<tblTestA> o IEnumerable<tblTestB>.

Su foreach los bucles de trabajo.Como alternativa, puede utilizar Cast para cambiar los tipos:

List<TestInterface> list = new List<TestInterface>();
list.AddRange(a.Cast<TestInterface>());
list.AddRange(b.Cast<TestInterface>());

El AddRange está esperando una lista de objetos de la interfaz, y sus varáficas "A" y "B" se definen para ser una lista de objetos de clase derivados.Obviamente, parece razonable que .NET podría hacer lógicamente ese salto y tratarlos como listas de los objetos de la interfaz porque realmente implementan la interfaz, esa lógica no se acumularía en .NET hasta 3.5.

Sin embargo, esta habilidad (llamada "covarianza") se ha agregado a .NET 4.0, pero hasta que se actualice a eso, estará atrapado con el bucle, o tal vez intente llamar a Toarray () y luego colocar el resultado a unTaskInterface [], o tal vez una consulta LINQ para caso de cada artículo y cree una nueva lista, etc.

a y b son de tipo IEnumerable<tblTestA> y IEnumerable<tblTestB>
Mientras list.AddRange requieren el parámetro de tipo IEnumerable<TestInterface>

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top