2012-05-25 1 views
6

Ich habe ein wenig über generische Varianz gelesen und ich habe noch kein volles Verständnis davon, aber ich würde gerne wissen, ob es so etwas wie das Folgende möglich macht?Kann C# 4.0-Varianz mir helfen, einen Basisklassenkonstruktor mit einem Upcast aufzurufen?

class A<T> { } 

class B { } 

class C : B { } 

class My1 { 
    public My1(A<B> lessDerivedTemplateParameter) 
    { 
    } 
} 

class My2 : My1 { 
    public My2(A<C> moreDerivedTemplateParameter) 
     : base(moreDerivedTemplateParameter) // <-- compile error here, cannot convert 
    { 
    } 
} 
+1

Ich bin nicht so fließend in der generischen Variante ce, wie ich sein möchte, daher ist dies ein Kommentar, keine Antwort, aber ich denke, Sie müssen 'A ' definieren als 'A ', um dies zu kompilieren. – psubsee2003

+3

@ psubse2003: Ich glaube, das ist nur für Schnittstellen erlaubt. – Douglas

+0

interessant, ich habe Ihren Vorschlag plus musste A und Schnittstelle machen, dann kompiliert es ... ich werde weitermachen und sehen, ob ich das gleiche Ergebnis erhalten kann, war ich nach, danke ... –

Antwort

6

Nein, denn während C erbt von B, A<C> von A<B> nicht erben wird.

Um zu verstehen, warum dies der Fall ist, vorstellen, wenn A<T> statt List<T> sind:

class B { } 

class C : B { } 

class D : B { } 

class My1 { 
    public My1(List<B> lessDerivedTemplateParameter) 
    { 
     // This is totally legal 
     lessDerivedTemplateParameter.Add(new D()); 
    } 
} 

class My2 : My1 { 
    public My2(List<C> moreDerivedTemplateParameter) 
     // if this were allowed, then My1 could add a D to a list of Bs 
     : base(moreDerivedTemplateParameter) 
    { 
    } 
} 

nun auf der anderen Seite, das ist legal:

interface IA<out T> { 
    public T GetSome(); 
} 

class B { } 

class C : B { } 

class D : B { } 

class My1 { 
    public My1(IA<B> lessDerivedTemplateParameter) 
    { 
     // This is totally legal 
     var someB = lessDerivedTemplateParameter.GetSome(); 
    } 
} 

class My2 : My1 { 
    public My2(IA<C> moreDerivedTemplateParameter) 
     // This is allowed, because an A<C> only *produces* C's (which are also B's) 
     // so the base class (which consumes B's, and doesnt care if they are C's) 
     // can use an IA<C> 
     : base(moreDerivedTemplateParameter) 
    { 
    } 
} 
+0

Das ist richtig, aber verfehlt den Punkt der Frage. Er weiß *, dass das aktuelle Setup nicht funktioniert, und möchte wissen, ob er die Varianz nutzen kann, um diese Situation zu ändern. Du hast gerade neu formuliert, was er bereits weiß. – dlev

+0

@dlev Ich habe eine Illustration hinzugefügt, was * funktioniert * –

+0

Nizza. +1 tatsächlich. – dlev

2

Sie A als Schnittstelle deklarieren mit einem kontravarianten Typ Parameter und es wird kompilieren:

internal interface A<out T> 
    { 
    } 

    internal class B 
    { 
    } 

    internal class C : B 
    { 
    } 

    internal class My1 
    { 
    public My1(A<B> lessDerivedTemplateParameter) 
    { 
    } 
} 

internal class My2 : My1 
{ 
    public My2(A<C> moreDerivedTemplateParameter) 
     : base(moreDerivedTemplateParameter) 
    { 
    } 

} 
+1

die kritische Sache hier zu beachten ist, dass dies einschränkt, dass A nur produzieren (und nicht verbrauchen) Typ T. –

+0

@ChrisShain, und das ist die Verbindung zu Bedeutung von "out" richtig? –

+0

@AaronAnodide das ist richtig –

Verwandte Themen