2017-06-07 2 views
0

Ich versuche, etwas zu bekommen, das mit dem unten stehenden arbeitet und kämpft, wenn ich Contravariance benutze. Mein Verständnis ist Covariance ist, wo Sie einen abgeleiteten Typ von einem Basistyp zurückgeben können. Kontravarianz ist, wo Sie einen abgeleiteten Typ von einem Basistyp als Argument in eine Klasse übergeben können. SoC# .net 4.0 Covariant vs Contravariant

Ich habe die unten Schnittstelle (kontra):

public interface IBase<in T> where T: BaseModel 
{ 
     void Process(T model); 
} 

Ich habe dann eine abstrakte Klasse

public abstract class Base<T>: IBase<T> where T: BaseModel 
{ 
    public virtual void Process(T model) 
    { 
     // throw new System.NotImplementedException(); 
    } 
} 

und andere konkrete Klasse

public class Parent: Base<ParentModel> 
{ 
    public override void Process(ParentModel model) 
    { 
     // throw new System.NotImplementedException(); 
    } 
} 

Unter Berücksichtigung der gattungs nur als Eingabe und nicht als Rückgabetyp verwendet, sehe ich nicht, warum ich das unten nicht tun kann:

IBase<BaseModel> baseContravariant = new Parent(); 
// This doesn't compile. I will eventually have a list of IBase<BaseMode> to which I'd like to pass in different parent instances. 

Ich habe ein anderes Beispiel mit Kovarianz, die unten ist und funktioniert gut.

public interface IBase<out T> where T : BaseModel, new() 
{ 
    T ProcessAndGet(); 
} 

Zusammenfassung

public abstract class Base<T>: IBase<T> where T: BaseModel, new() 
{ 
    public virtual T ProcessAndGet() 
    { 
     var result = new T() as BaseModel; 

     // More shizzle here 
     return (T)result; 
    } 
} 

Beton

public class Parent : Base<ParentModel> 
{ 
    public override ParentModel ProcessAndGet() 
    { 
     var x = base.ProcessAndGet(); 
     return x; 
    } 
} 

Jetzt kann ich

IBase<BaseModel> baseInstance = new Base<BaseModel>(); 
IBase<BaseModel> derived = new Parent(); 
baseInstance = derived; 

tun es mehr Code auf die obigen Beispiele, aber ich habe es für eine einfache entfernt Lesen (hoffentlich!) :-)

Antwort

0

Kontravarianz bedeutet in diesem Fall, dass Sie Typen vom angegebenen Typ übergeben müssen oder eine, die "spezieller" ist (=> vom Basistyp abgeleitet wird).

Da Ihre Parent Implementierung in Ihrem ersten Beispiel nur ParentModel verarbeiten kann, ist es ungültig, eine BaseModel Instanz zu übergeben. Der Versuch, zu tun, würde auch nicht kompilieren. Daher ist es ungültig, sie auf IBase<BaseModel> zu übertragen. (angenommen ParentModel ist eine Unterklasse von BaseModel).

In diesem Fall ist das Kontravarianzmodell einfacher zu denken, indem man denkt, dass ein IBase<in T> "ein T verbraucht". So ein IBase<ParentModel> "verbraucht ParentModel s". Dies bedeutet, dass nur Werte übergeben werden können, die Instanzen von sind oder als eine Einheit behandelt werden können (effektiv nur Unterklassen).

In Ihrem zweiten Beispiel verwenden Sie <out T>, die "kovariant" ist. Dies kann als "es erzeugt Instanzen von T" beschrieben werden. Eine Klasse, die eine ParentModel "produziert", ist automatisch auch ein "Produzent" von BaseModel: da ParentModel auf BaseModel verkettet werden kann, kann IBase<ParentModel> auch auf IBase<BaseModel> geworfen werden.

+0

Danke für die Antwort und informative Antwort. Das zweite Beispiel, das ich zur Verfügung gestellt habe, macht ähnliche Schritte. Die Eltern-Klasse nimmt nur ParentModel an, aber ich kann dies immer noch der Basisklasse zuweisen? Ich dachte, das war die Absicht hinter dem In/Out-Feature ... – tones

+0

Ich fügte einen Absatz über den kovarianten Typ hinzu.Ich bin nicht ganz sicher, was Ihre eigentliche Frage dafür ist, um ehrlich zu sein ... (außer das Erklären es in den einfacheren Wörtern. Das Ersetzen alles mit "Produzent" und "Verbraucher" half mir immer, dieses Zeug herauszufinden) –

+0

Aah, der Sinn macht . Es gab keine Frage über den zweiten Punkt. Es war, als ob du mehr sagst, um die beiden zu vergleichen, so wie das eine funktionierte und das andere nicht. Kurz gesagt für Kovarianz können Sie weniger spezifische Typen zuweisen, aber Kontravarianz können Sie nicht. Hoffentlich habe ich das richtig verstanden. – tones