2011-10-03 9 views
15

Ho una funzione come questa:Come passare l'elenco di classe a Elenco di interfaccia?

DoSomething(List<IMyInterface>) 

IMyInterface è un'interfaccia e MyClass è una classe che implementa questa interfaccia classe MyClass: IMyInterface

chiamo DoSomething(List<MyClass>) e sembra che non funziona. Come posso passare l'elenco di una classe a un elenco dell'interfaccia della classe come parametro della funzione? Grazie!

+0

qual è il tuo codice? – talnicolas

risposta

26

Se il codice è semplicemente iterazione di sequenza all'interno del metodo (non aggiunta, la rimozione o l'accesso per indice), cambiare il metodo di una delle seguenti

DoSomething(IEnumerable<IMyInterface> sequence) 
DoSomething<T>(IEnumerable<T> sequence) where T : IMyInterface 

L'interfaccia IEnumerable<> è covariante (come di .NET 4) (prima opzione). Oppure puoi utilizzare quest'ultima firma se usi C# 3.

Altrimenti, se hai bisogno di operazioni indicizzate, converti l'elenco prima di passarlo. Nel invocazione, si potrebbe avere

// invocation using existing method signature 
DoSomething(yourList.Cast<IMyInterface>().ToList()); 

// or updating method signature to make it generic 
DoSomething<T>(IList<T> list) where T : IMyInterface 

Che quest'ultimo firma permetterebbe di fare è quello di sostenere anche aggiunge o rimuove alla lista (visibile in callsite), e sarebbe anche consentire di utilizzare la lista senza prima copiandolo.

Anche se tutto ciò che fai è scorrere l'elenco in un ciclo, preferirei un metodo che accetta IEnumerable<>.

+0

Per operazioni indicizzate e rimozione, non sarebbe 'DoSomething (elenco IList ) dove funziona anche T: IMyInterface'? (Senza la necessità di copiare l'elenco.) – millimoose

+0

@Sli, sì, potrebbe rendere il metodo generico. Ho aggiornato per mostrare le opzioni generiche. –

+0

Un'alternativa sarebbe quella di definire un'interfaccia IReadableList e quindi scrivere una classe wrapper che implementa sia quella che IList . Sfortunatamente, un altro codice dovrebbe essere cambiato per usare la classe wrapper. Si potrebbe definire una conversione di ampliamento da un List a ListWrapper , ma sarebbe un po 'icky e non aiuterebbe il sistema a riconoscere che un Elenco può essere trasformato in qualcosa (un ListWrapper ) che implementa IReadableList . – supercat

7

Questo non è sicuro in generale perché le liste sono modificabili. Supponiamo che si passa qualcuno un riferimento a un List<MyClass> come List<IMyInterface>, poi fanno:

void Foo(List<IMyInterface> list) 
{ 
    IMyInterface x = new MyOtherClassWhichAlsoImplementsIMyInterface(); 
    list.Add(x); 
} 

Ora il vostro List<MyClass> contiene un'istanza di una classe che non è un MyClass. Ciò violerebbe la sicurezza del tipo. (Come osservato in altre risposte, è possibile evitare questo problema passando solo l'interfaccia IEnumerable<> di List, che fornisce accesso in sola lettura e quindi è sicuro).

Per ulteriori dettagli, vedere Using Variance in Interfaces for Generic Collections on MSDN. Vedi anche a good summary of covariance and contravariance and various C# features that support it.

0

Se è sufficiente scorrere l'elenco, dichiarare il metodo con IEnumerable. Se si desidera aggiungere elementi all'elenco, ciò che si sta chiedendo non è tipicamente corretto e potrebbe non essere consentito in C# come risultato.

Problemi correlati