2017-12-21 7 views
0

den folgenden Code vor:Wie ein generisches an die Schnittstelle werfen es implementiert, wenn die Parameter des Typs auf beide eine gemeinsame Schnittstelle in C# implementieren

public class Thing : IThing { } 

public interface IThing {} 

public interface IContainer<out T> where T : IThing { } 

// This works 
// public class Container<T> : IContainer<T> where T : IThing { } 

// This doesn't work 
public class Container<T> : IContainer<IThing> where T : IThing {} 

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
    var concreteContainer = new Container<Thing>(); 
    var abstractContainer = (IContainer<Thing>) concreteContainer; 
    } 
} 

Auf dieser Linie:

var abstractContainer = (IContainer<Thing>) concreteContainer; 

Sie erhalten der folgende Laufzeitfehler: InvalidCastException: Unable to cast object of type 'CastTest.Container`1[CastTest.Thing]' to type CastTest.IContainer`1[CastTest.Thing]'.

Auch wenn Sie Resharper haben, klagt es mit, Suspecious cast: there is no type in the solution which is inherited from both 'Container<Thing>' and 'IContainer<Thing>'.

Warum muss es einen Typ geben, der von beiden erbt? Nicht Container<T> implementieren IContainer<IThing>? Da Thing implementiert IThing, und T in Container<T> ist garantiert, IThing zu implementieren, scheint es, wie ich in der Lage sein sollte, diese Besetzung zu tun.

+1

'Container ' implementiert 'IContainer ' nicht 'IContainer '. – Lee

+0

@hvd Was, jetzt willst du, dass ich tatsächlich aufpasse ?! Mensch, Leute fragen viel. Hoppla! –

Antwort

2

Doesn't Container<T> implement IContainer<IThing> ?

Es tut es.

Since Thing implements IThing , and T in Container<T> is guaranteed to implement IThing , it seems like I should be able to do this cast.

out funktioniert umgekehrt. out bedeutet, dass, wenn der Typ IContainer<Thing> implementiert, auch automatisch IContainer<IThing> implementiert wird. Nicht umgekehrt.

Es heißt out, weil es etwas zurückgeben kann. Sie könnten zum Beispiel haben

interface IThing<out T> { 
    T Prop { get; } 
} 

Nun IContainer<Apple> automatisch IContainer<Fruit> implementieren würde, und IContainer<Banana> würde auch IContainer<Fruit> automatisch implementieren. Das funktioniert, weil etwas, das eine Apple zurückgibt, so interpretiert werden kann, dass es eine Fruit zurückgibt. Aber wenn Sie nur wissen, dass es einen Fruit zurückgibt, wissen Sie nicht, ob das Fruit ein Apple ist.

in funktioniert so, wie Sie fragen. Sie könnten zum Beispiel haben

interface IThing<in T> { 
    void Act(T t); 
} 

Nun IContainer<Apple> tut nicht automatisch IContainer<Fruit> implementieren. Das ist, weil etwas, das eine Apple erfordert, nicht in der Lage ist, beliebige Fruit s zu akzeptieren. Aber etwas, das nur eine Fruiterfordert, tut akzeptieren alle Apple s.

+0

Danke. Dies war der Schlüssel zu meinem Verständnis, "... etwas, das erfordert, dass Apple keine willkürlichen Früchte akzeptieren kann. Aber etwas, das nur eine Frucht erfordert, akzeptiert alle Äpfel." – watkipet

Verwandte Themen