2012-06-20 9 views
9

Mam ten prosty kod:NET kowariancji

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

Interfejs ten należy kowariantna na T, i używam go w ten sposób:

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

Uwaga ograniczenie dla T do wdrożenia IComposite. Metoda synchronizacji trwa IReader<IComposite> na wejściu:

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

Kompilator mówi mi, że nie można przekonwertować z IReader<T> do IReader<IComposite> pomimo ograniczenia na T i kowariancji iReader.

Czy jest coś, co robię źle tutaj? Kompilator powinien być w stanie zweryfikować ograniczenie, a kowariancja powinna pozwolić mi używać mojego IReader<T> jako IReader<Icomposite>, czyż nie?

Dzięki.

+3

Co jeśli 'T' jest strukturą? Wtedy zasady wariancji zostaną zerwane. Aby przekonać kompilator, że będzie to konwersja zachowująca tożsamość, potrzebne jest ograniczenie "class". Zobacz: [Czy jest to błąd kowariancji w C# 4?] (Http://stackoverflow.com/questions/2783233/is-this-a-covariance-bug-in-c-sharp-4) – Ani

+0

tak, to było problem, teraz działa dobrze. dziękuję –

+0

możliwy duplikat [Dlaczego kowariancja nie działa z metodą ogólną] (http://stackoverflow.com/questions/12743444/why-covariance-does-notwork-z-generic-method) – nawfal

Odpowiedz

5

Powinieneś być w stanie rozwiązać swój problem przez dodanie ograniczenia class do T. Kowariancja nie działa, gdy struktura jest zaangażowana (IEnumerable<int> nie może być przekształcana na IEnumerable<object>). Ponieważ nie ograniczyłeś T, aby zostać klasą, możesz przekazać IReader<some struct that implements IComposite>, który nie byłby zamienny.

+0

fajne, działa teraz, już wiedziałem, że kowariancja nie działa z typów wartości, ale nie zdawałem sobie sprawy, że to jest przyczyną mojego problemu w tym przypadku. dodanie ograniczenia klasy sprawia, że ​​działa idealnie. Dziękuję Ci !! –

1

Niestety nie. Generics nie są kowariantne. IReader<T> i IReader<IComposite> są całkowicie niepowiązanymi typami, pomimo że T są powiązane z IComposite.

EDYTOWANIE: Nie wiem, dlaczego to nie zadziała z .Net 4 i <out T>. Czy ktoś inny może odpowiedzieć?

+1

jesteś pewien? specyfikator wyjścia w definicji interfejsu IReader powinien powiedzieć kompilatorowi, że interfejs jest kowariancyjny. używam .NET 4 –

+3

Ta odpowiedź wymaga wyjaśnienia; to jest dość mylące, jak napisane. –

+0

Nie wiedziałem o parametrze dla kowariancji interfejsu, a po przeczytaniu tego nie rozumiem, dlaczego kod OP nie zadziałałby. +1 za pytanie, odkąd się czegoś nauczyłem i mam nadzieję, że ktoś inny może odpowiedzieć. – GazTheDestroyer

0

Dlaczego nie zmienić definicję funkcji, ponieważ to jest to, czego naprawdę chcą coś:

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

może zaistnieć potrzeba rodzajowego parametr T na inne rzeczy, więc zostawiłem go tam.

+0

ponieważ potrzebuję parametru T dla czegoś innego, to był tylko przykład, a nie prawdziwy kod. i chciałbym, aby kompilator wypowiadał typ T zamiast go wyraźnie określać. –