2009-08-11 6 views
6

wäre das möglich? (Ich habe nicht gegen 2010, also kann ich es selbst nicht versuchen, sorry)IList Verwendung von Kovarianz und Kontravarianz in C#, ist das möglich?

public interface IComplexList<out TOutput, in TInput> where TOutput : TInput 
{ 
    public IEnumerator<TOutput> GetEnumerator(); 
    public void Add(TInput item); 
} 

public interface IList<T> : IComplexList<T, T> 
{ 
} 

Wenn ich es richtig machen, könnten Sie diese verwenden, um tatsächlich Kovarianz und Kontra in der gleichen Schnittstelle zu implementieren.

Antwort

5

Nein, das geht nicht. In Ihrem Beispiel ist IList<T> invariant. IList<T> würde erfordern, dass in/out kovariant/kontravariant zu sein. Dies ist nicht möglich, indem nur eine Schnittstelle erbt wird, die kovariant ist.

8

Nun, Ihre Frage ist etwas verwirrend wegen der bestehenden IList<T> Art. Allerdings ist die folgende Kompilierung:

public interface IComplexList<out TOutput, in TInput> where TOutput : TInput 
{ 
    IEnumerator<TOutput> GetEnumerator(); 
    void Add(TInput item); 
} 

public interface ISimpleList<T> : IComplexList<T, T> 
{ 
} 

Sie können es sogar ändern IEnumerable<TOutput> zu erweitern:

public interface IComplexList<out TOutput, in TInput> 
    : IEnumerable<TOutput> 
    where TOutput : TInput 
{   
    void Add(TInput item); 
} 

public interface ISimpleList<T> : IComplexList<T, T> 
{ 
} 

Der Indexer ist heikel, weil Sie beteiligt wollen würden verschiedene Typen. Sie tun können:

TOutput Get(int index); 
void Set(int index, TInput item); 

und dann den Indexer in ISimpleList<T> anstelle natürlich ...

setzen, die Sie ISimpleList<T> nicht benutzen lassen variantly aber, weil man im Grunde TInput = TOutput gezwungen haben.

Ein alternativer Ansatz ist die Eingabe von dem Ausgang zu trennen:

public interface IReadableList<out T> : IEnumerable<T> 
{ 
    T Get(int index); 
} 

public interface IWritableList<in T> 
{ 
    void Add(T item); 
    void Set(int index, T item); 
} 

public interface IMyList<T> : IReadableList<T>, IWritableList<T> {} 

Dann könnten Sie schreiben:

public void Foo(IWritableList<string> x) { ... } 

IMyList<object> objects = new MyList<object>(); 
Foo(objects); 

und umgekehrt für IReadableList. Mit anderen Worten, Sie erlauben Varianz für jede Seite einzeln, aber Sie erhalten nie Varianz für die beiden Seiten zusammen.

+0

Es kompiliert sicherlich, aber es wäre nicht co/kontra-Variante. 'ISimpleList ' kann nicht als 'ISimpleList ' verwendet werden. –

+0

Danke für den Versuch –

+0

Ich werde meine Antwort genauer zu aktualisieren - Entschuldigung, immer noch all dies durchdenken. –

0

Wenn eine Implementierung einer Lese-Schreib-Eigenschaft auch als Implementierung einer schreibgeschützten Eigenschaft betrachtet wurde, könnte man eine nützliche Form der List-Kovarianz und -Kontravarianz hinzufügen, indem IList (von T) von IReadableList (von Out T abgeleitet wird)) und IAddableList (von In T). Vorausgesetzt, dass diese Schnittstellen einfach Elemente enthielten, die in IList (Of T) vorhanden waren, bevor sie definiert wurden, implementierte ein Code, der IList (Of T) implementierte, automatisch diese anderen Elemente. Damit IReadableList kovariant ist, müsste es leider eine schreibgeschützte Indexereigenschaft haben; Die Implementierung der Lese-Schreib-Eigenschaft in IList konnte nicht ersetzt werden. Wenn IList (Of T) von einer verwendbaren IReadableList (Of Out T) erbt würde, würde dies alle Implementierungen von IList (Of T) durchbrechen.