2016-07-27 15 views
3

Ich versuche, eine generische Möglichkeit zu erstellen, um zu halten, welche Eigenschaft ich gegen eine gegebene Klasse suchen sollte.Erstellen von generischen mit Unterklasse

Ich habe die folgende Struktur geschaffen, diese Informationen zu halten:

public struct Lookup<T> where T: BaseEntity 
{    
    public Expression<Func<T, object>> Parent { get; set; } 
} 

Und dann ein Wörterbuch erstellt haben, wie folgt:

readonly Dictionary<string, Lookup<BaseEntity>> _dict = 
    new Dictionary<string, Lookup<BaseEntity>>(); 

Ich habe eine Klasse, die die BaseEntity als Basisklasse verwendet :

public class Agency : BaseEntity 
{ 
    public int AgencyId { get; set; } 
} 

Ich erstelle eine neue Lookup-Struktur mit dieser Information:

new Lookup<Agency> 
{ 
    Parent = x => x.Id 
}; 

Aber wenn ich versuche, diese zu meinem Wörterbuch bekomme ich folgende Fehlermeldung:

Cannot convert from Lookup<Agency> to Lookup<BaseEntity>

Ich hätte gedacht, dass dies funktionieren würde, wie sie von dem gleichen Basistyp sind, was ist der Weg ringsum.

ich eine ganze Reihe von Entitäten hinzuzufügen, so hatte gehofft, dass es allgemein zu tun, anstatt zu tun haben, wenn/Schalter usw.

Dank

+2

Lesen Sie in Kovarianz: sowieso Sie gehen mit den nicht typisierten Expression s zu arbeiten - Während Sie starke Typisierung müssen Lookup<Agency> erstellen, brauchen Sie es nicht in der Art selbst. –

Antwort

3

Nein, Lookup<BaseEntity> ist kein Basistyp Lookup<Agency>. Die Tatsache, dass Agency von BaseEntity abgeleitet ist, ist nicht genug. Aber zuerst, schauen wir uns etwas anderes an.

Denken Sie über die üblichen Varianzregeln nach. Ihre Methode entspricht

object DoSomething(T x) { ... } 

nun in Lookup<BaseEntity>, dies wird

object DoSomething(BaseEntity x) { ... } 

So weit, so gut - es vollkommen legal ist Agency anstelle von BaseEntity zu passieren, da Agency von BaseEntity ableitet. Dies ist jedoch nicht der Fall Sie haben. Sie haben dieses:

object DoSomething(Agency x) { ... } 

Natürlich können Sie nicht BaseEntity passieren statt Agency - das ist die Eingabe vollständig brechen würde. Und im Gegensatz zu Java sind C# - (und allgemein .NET) Generika sowohl in der Kompilierungszeit als auch in der Laufzeit real und fallen nicht auf Lookup<BaseEntity> zurück.

Darüber hinaus begrenzt C# /. NET die Verwendung der Varianz. Sie erhalten eine freie Varianz in einfachen Ausdrücken und Delegaten, aber nicht in Klassen oder generischen Klassen. Sie müssen explizit über die Art der Abweichung, die Sie wollen, und verwenden Sie eine Schnittstelle. Zum Beispiel, in Ihrem Fall, würden Sie so etwas wie dieses:

public interface ILookup<out T> 

Dies würde ermöglichen es Ihnen, die Besetzung von ILookup<Agency> zu ILookup<BaseEntity> zu tun. Es ist jedoch nicht genug für Ihren Fall, da T in Ihrem Fall sowohl co-Variante als auch Kontra-Variante ist - mit anderen Worten, Sie können nicht in beide Richtungen werfen.

Dies ist jedoch keine große Sache, da Sie die Dinge ein wenig zu kompliziert machen.

public sealed class Lookup 
{ 
    private readonly Expression parent; 

    private Lookup(Expression parent) 
    { 
    this.parent = parent; 
    } 

    public Expression Parent { get { return parent; } } 

    public static Lookup For<T>(Expression<Func<T, object>> member) 
    where T : BaseEntity 
    { 
    return new Lookup(member); 
    } 
} 
+0

Super! Gute Antwort. – niksofteng

+0

Nun, ich habe keine so gute Antwort erwartet! Es war genau das, wonach ich gesucht habe, danke für deine Hilfe! – ADringer

Verwandte Themen