Domanda

Ho un'interfaccia definita come di seguito:

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

e due classi LINQ-to-SQL implementano quell'interfaccia:

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

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

Ho elenchi IeNumerabili A e B popolati dai record del database da TBLTESTA e TBLTESTB

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

Tuttavia, non è consentito quanto segue:

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

Devo fare come segue:

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

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

C'è qualcosa che sto sbagliando?Grazie per qualsiasi aiuto

È stato utile?

Soluzione

funziona in c # 4, a causa di covarianza generica . A differenza delle versioni precedenti di C #, c'è una conversione da IEnumerable<tblTestA> a IEnumerable<TestInterface>.

La funzionalità è stata nella CLR da V2, ma è stata esposta solo in C # 4 (ei tipi di framework non ne ha approfittato prima di .Net 4). IT si applica alle interfacce generiche e ai delegati (non classi) e solo per i tipi di riferimento (quindi non c'è conversione da IEnumerable<int> a IEnumerable<object> ad esempio.) Funziona anche solo dove ha senso - IEnumerable<T> è covariante Gli oggetti vengono solo "fuori" dell'API, mentre IList<T> è invariante perché è possibile aggiungere valori con quell'aPI anche.

Contravariance generico è supportato anche, lavorando nell'altra direzione - quindi ad esempio è possibile convertire da IComparer<object> in IComparer<string>.

Se non stai usando C # 4, quindi il suggerimento di Tim di usare Enumerable.Cast<T> è buono - perdi una piccola efficienza, ma funzionerà.

Se vuoi saperne di più sulla varianza generica, Eric Lippert ha un Long Series of Blog Post A proposito , e ne ho parlato a NDC 2010 che puoi guardare sul Pagina video NDC .

Altri suggerimenti

Non stai facendo nulla di sbagliato: List<TestInterface>.AddRange si aspetta un IEnumerable<TestInterface>.Non accetterà un IEnumerable<tblTestA> o IEnumerable<tblTestB>.

I tuoi loops foreach funzionano.In alternativa, è possibile utilizzare Cast per modificare i tipi:

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

L'addrange si aspetta un elenco di oggetti di interfaccia, e i tuoi vaiblebles "A" e "B" sono definiti come un elenco di oggetti di classe derivati.Ovviamente, sembra ragionevole che .Net possa logicamente farlo saltare e trattarli come elenchi degli oggetti di interfaccia perché implementano in effetti l'interfaccia, quella logica non è stata semplicemente costruita in 3.5.

Tuttavia, questa abilità (chiamata "Covariacce") è stata aggiunta a .NET 4.0, ma finché non aggiorni a questo, sarete bloccati con looping, o forse prova a chiamare Torreray () e quindi lanciare il risultato a ATaskInterface [], o forse una query LINQ per caso ogni elemento e creare un nuovo elenco, ecc.

a e b sono di tipo IEnumerable<tblTestA> e IEnumerable<tblTestB>
Mentre list.AddRange richiede che il parametro sia di tipo IEnumerable<TestInterface>

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top