2009-04-14 12 views
8

Mögliche Duplizieren:
Why cannot C# generics derive from one of the generic type parameters like they can in C++ templates?generische Vererbung in C#?

I

public class MyGenericClass : DL 
//but i cannot do 
public class MyGenericClass <T> : T 

tun können, Wie würde ich tun, um die zweite? wenn ich das nicht tun kann, wie kann ich etwas tun, wie

public class MyGenericClass <T> 
{ 
    T obj; 
    //have all MyGenericClass.XYZ call obj.XYZ 
} 
+0

Was ist deine Motivation dafür? –

+0

Warten Sie in C# 4.0 auf den dynamischen Typ. –

Antwort

9

dies nicht möglich ist, weil je nachdem, welche Art T ist, würde sich ändern, die öffentliche Schnittstelle von MyGenericClass.

Wenn Sie viele verschiedene Klassen, die alle die gleiche Schnittstelle aussetzen, könnten Sie MyGenericClass erklären, dass die Schnittstelle zu belichten, und bei der Umsetzung der alle Funktionen, die Anrufe delegieren obj

+0

Aber im zweiten Fall, wo T verwendet wird, um ein Mitglied zu deklarieren, könnte dieses Mitglied öffentlich sein, und dann würde sich die öffentliche Schnittstelle von MyGenericClass abhängig vom Typ von T ändern. –

+0

Nur der Datentyp der Eigenschaft, der von Natur aus behandelt wird durch .net und Generika. Mein Punkt war mehr, dass ganze Funktionen und Eigenschaften hinzugefügt und entfernt würden, wenn es so funktionierte, wie er wollte, und nicht eine Datentypänderung –

+0

Das ist zirkulär: "inhärent von Generika gehandhabt" - warum behandelt es nicht inhärent den Fall, der nicht funktioniert t arbeiten? :) –

4

Sie etwas tun könnte, wie

public interface IXyzable { void xyz(); } 

public class MyGenericClass<T> : IXyzable where T : IXyzable { 
    T obj; 
    public void xyz() { 
     obj.xyz(); 
    } 
} 

Edit: Jetzt verstehe ich die Frage

+0

Könnten Sie mir bitte einen Arbeitscode geben, um diese Klassenfunktion aufzurufen? – Elangesh

+0

Ich habe den folgenden Code verwendet MyGenericClass myGenericClass = new MyGenericClass (); Console.WriteLine (myGenericClass.xyz()); Konsole.ReadLine(); – Elangesh

+0

checkout http://stackoverflow.com/questions/3419176/how-to-use-the-where-keyword-in-c-sharp-with-a-generic-interface-and-inherita –

0

Sie benötigen alle möglichen T ist eine Schnittstelle zu implementieren, so dass Sie wissen, dass obj.XYZ() Sinn macht, dann kann man tun

public interface Ixyz 
{ 
    void XYZ(); 
} 

public class MyGenericClass<T> : Ixyz where T:Ixyz, new() 
{ 
    T obj; 

    public MyGenericClass() 
    { 
     obj = new T(); 
    } 

    public void XYZ() 
    { 
     obj.XYZ(); 
    } 
} 

Ich habe gemacht MyGenericClass Ixyz implementieren, da es offensichtlich die richtige Methode verfügbar macht, aber vielleicht ist das am besten weggelassen, da es

var x = new MyGenericClass<MyGenericClass<SomeClass>>(); 

ermöglicht, die es unwahrscheinlich ist, immer eine gute Idee zu sein.

0

Dies ist ziemlich Ente Eingabe, aber Sie könnten Reflexion verwenden. Wenn Sie die generische Klasse mit einem Verweis auf das Objekt erstellen, verwenden Sie reflection, um eine Methode mit der richtigen Signatur zu finden. Solange Sie einen Verweis auf die Methode speichern, ist die Leistung nicht zu schlecht.

class BaseGeneric<T> 
{ 
    private T obj; 
    private MethodInfo mi; 
    private const string MethodNameOfInterest = "Xyz"; 

    public BaseGeneric(T theObject) 
    { 
     this.obj = theObject; 
     Type t = obj.GetType(); 
     mi = t.GetMethod(MethodNameOfInterest); 
    } 

    public void Xyz() 
    { 
     mi.Invoke(obj, null); 
    } 
} 

Natürlich würden Sie brauchen viel mehr für die Fehlerprüfung und so hinzuzufügen, aber das ist der Kern dessen, was man tun könnte. Vergessen Sie außerdem nicht, den System.Reflection-Namespace Ihrer using-Klausel hinzuzufügen.

+0

warum die down vote? Ich habe die Frage beantwortet, oder? Ich würde nicht empfehlen, es zu tun, aber es löst sein Problem: BaseGeneric .Xyz() ruft die Xyz() - Methode des zugrundeliegenden Objekts auf, egal, was dieser Typ ist. –

+0

Ihre Lösung hat alle Schattenseiten der Reflexion und keine Vorteile der Entenschrift. Für das externe Objekt (BaseGeneric) müssen alle Funktionen deklariert sein. Wenn Sie diese Funktionen kennen, rufen Sie einfach die gleiche Funktion auf? –

+0

Es speichert die MethodInfo, so dass die Leistungseinbußen reduziert werden. Es sieht aus wie das zugrunde liegende Objekt - also quakt es. Es bringt ihn dazu, jede Methode von Neuem zu implementieren, und das ist der größte Nachteil. T könnte jedoch alles sein, was Xyz implementiert, was in bestimmten Szenarien nützlich ist. –

1

Das .NET-Typsystem lässt Typdeklarationen des Formulars, das Sie versuchen, nicht zu. Ein Grund, warum dies nicht erlaubt ist, sollte intuitiv sein: Wie würde MyGenericClass<T> handeln, wenn T eine versiegelte Klasse ist (z. B. System.String)?

Wenn Sie diese Funktionalität absolut benötigen (und Sie wissen, dass der Typ T, den Sie verwenden, nicht versiegelt ist), können Sie Proxys zur Laufzeit unter Verwendung der Klassen im Reflection.Emit-Namespace generieren. Es ist auch möglich, diesen Effekt mit AOP-Tools wie PostSharp zu erreichen.

+0

MyGenericClass würde einen Compilerfehler erzeugen. Wenn dieses Sprachenfeature verfügbar wäre, würde die Vererbung von T T automatisch so festlegen, dass es entsiegelt wird. Obwohl dies nur ein Teil des Problems ist (siehe meine Antwort). –

4

Die spezifische Frage, warum können Sie nicht tun:

public class MyGenericClass<T> : T 

Und Sie können dies tun:

public class MyGenericClass<T> 
{ 
    T obj; 
} 

Der Grund dafür ist, dass die CLR mag eine einzige kompilieren zu können, Version des Codes für MyGenericClass, die für jeden Referenztyp funktioniert, der für T angegeben wird.

Es kann dies für den zweiten Fall tun, da es problemlos T durchersetzen kannund entsprechende Abgüsse einzufügen, entspricht in etwa:

public class MyGenericClass 
{ 
    object obj; 
} 

Aber für die Vererbung Version, dass Trick funktioniert nicht.

Auch viele nützliche Einrichtungen wären durch Schnittstellenbeschränkungen unmöglich zu beschreiben. Wenn Sie von einem Typ erben, können Sie viel mehr tun, als nur Methoden aufzurufen - Sie können sie auch überschreiben. Betrachten Sie dieses hypothetische Beispiel:

class MyBase 
{ 
    public virtual void MyVirtual() { } 
} 

class MyGenericDerived<T> : T 
{ 
    public override void MyVirtual() 
    { 
     Console.WriteLine("Overridden!"); 
    } 
} 

MyBase obj = new MyGenericDerived<MyBase>(); 
obj.MyVirtual(); 

Was ich tun möchte, so etwas wie ein „Mix-in“ ist, wo MyGenericDerived Definitionen für virtuelle Funktionen liefert in welcher Basis es angewendet wird. Aber wie weiß der Compiler, dass T eine Methode namens MyVirtual haben wird, die außer Kraft gesetzt werden kann? Ich müsste T einschränken. Wie würde ich das über Schnittstellen ausdrücken? Es ist unmöglich. Die Verwendung von Schnittstellen zur Beschreibung von Einschränkungen ist keine angemessene Lösung, wenn Sie die Vererbung von Typparametern zulassen. Das ist ein weiterer Grund, warum es heute in der Sprache nicht existiert.

0

Was dazu:

class BaseClass<T> 
{ 
    public T property { get; set; } 
} 

class GenericClass<T> : BaseClass<T> 
{ 

} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     GenericClass<int> l = new GenericClass<int>(); 
     l.property = 10; 
    } 
} 

Dadurch wird erreicht, was Sie tun wollen?

+0

Ich glaube nicht. Er möchte, dass GenericClass alle Methoden von T freilegt, ohne irgendetwas neu zu implementieren. Zumindest ist das meine beste Schätzung, was er verlangt. –