2012-06-20 14 views
9

ho questo semplice codice:.NET covarianza

public interface IReader<out T> 
{ 
    IEnumerable<T> GetData(); 
} 

Questa interfaccia deve essere covariante su T, e sto usando in questo modo:

private static Func<bool> MakeSynchroFunc<T>(IReader<T> reader) where T : IComposite 
{ 
    return() => Synchronize(reader); 
} 

Nota il vincolo per T implementare IComposite. Il metodo di sincronizzazione prende un IReader<IComposite> in ingresso:

private static bool Synchronize(IReader<IComposite> reader) 
{ 
    // ...... 
} 

Il compilatore mi dice che non può convertire IReader<T>-IReader<IComposite> nonostante il vincolo sulla T e la covarianza di iReader.

C'è qualcosa che sto facendo male qui? Il compilatore dovrebbe essere in grado di verificare il vincolo e la covarianza dovrebbe lasciarmi usare il mio IReader<T> come IReader<Icomposite>, non è vero?

Grazie.

+3

E se "T" fosse una struttura? Quindi le regole di varianza sarebbero rotte. È necessario un vincolo 'class' per soddisfare il compilatore che sarà una conversione che preserva l'identità. Vedi: [Si tratta di un bug di covarianza in C# 4?] (Http://stackoverflow.com/questions/2783233/is-this-a-covariance-bug-in-c-sharp-4) – Ani

+0

sì, quello era il problema, ora funziona bene. grazie –

+0

possibile duplicato di [Perché la covarianza non funziona con il metodo generico] (http://stackoverflow.com/questions/12743444/why-covariance-does-not-work-with-generic-method) – nawfal

risposta

5

Dovresti riuscire a risolvere il problema aggiungendo un vincolo class a T. La covarianza non funziona quando sono coinvolte le strutture (IEnumerable<int> non è convertibile in IEnumerable<object>). Dal momento che non hai vincolato lo T per diventare un corso, potresti passare in uno IReader<some struct that implements IComposite>, che non sarebbe convertibile.

+0

cool, funziona ora, sapevo già che la covarianza non stava funzionando con i tipi di valore, ma non mi ero reso conto che questa era la causa del mio problema in questo caso. l'aggiunta del vincolo di classe lo rende perfettamente funzionante. grazie !! –

1

Sfortunatamente no. I generici non sono covarianti. IReader<T> e IReader<IComposite> sono tipi totalmente indipendenti, nonostante lo T sia correlato allo IComposite.

EDIT: Non so perché questo non funzionerebbe con .Net 4 e <out T>. Qualcun'altro può rispondere?

+1

sei sicuro? lo specificatore esterno sulla definizione dell'interfaccia IReader dovrebbe dire al compilatore che l'interfaccia è covariante. sto usando .NET 4 –

+3

Questa risposta ha bisogno di chiarimenti; è piuttosto confuso come scritto. –

+0

Non conoscevo la parola chiave per la covarianza dell'interfaccia, e dopo aver letto su di essa non riesco a capire perché il codice dell'OP non funzionerebbe. +1 per domanda da quando ho imparato qualcosa, e spero che qualcun altro possa rispondere. – GazTheDestroyer

0

perché non cambiare la definizione della funzione, dal momento che questo è ciò che si vuole veramente nulla:

private static Func<bool> MakeSynchroFunc<T>(IReader<IComposite> reader) where T : IComposite 

Potrebbe essere necessario il parametro generico T per altre cose, quindi ho lasciato lì.

+0

perché ho bisogno del parametro T per qualcos'altro, questo era solo un esempio, non il codice reale. e vorrei che il compilatore inferisse il tipo di T invece di doverlo specificare esplicitamente. –