2009-04-14 5 views
8

Eventuali duplicati:
Why cannot C# generics derive from one of the generic type parameters like they can in C++ templates?ereditarietà generica in C#?

posso fare

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

come faccio a fare il secondo? Se non riesco a farlo, come posso fare qualcosa di simile

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

qual è la tua motivazione per provare a farlo? –

+0

Attendi il tipo dinamico in C# 4.0. –

risposta

9

Questo non è possibile, perché in base alla T tipo è, l'interfaccia pubblica di MyGenericClass cambierebbe.

Se hai un sacco di diverse classi che espongono tutti la stessa interfaccia, si potrebbe dichiarare MyGenericClass per esporre tale interfaccia, e nella realizzazione di tutte le funzioni delegare le chiamate a obj

+0

Ma nel secondo caso, dove T è usato per dichiarare un membro, quel membro potrebbe essere pubblico, e quindi l'interfaccia pubblica di MyGenericClass cambierebbe a seconda del tipo di T. –

+0

Solo il tipo di dati della proprietà, che è gestito in modo inerente da .net e generici. Il mio punto era che tutte le funzioni e le proprietà sarebbero state aggiunte e rimosse se funzionasse come voleva, non cambiando un tipo di dati –

+0

Questo è circolare: "intrinsecamente gestito dai generici" - perché non gestisce intrinsecamente il caso che non lo fa lavoro? :) –

4

Si potrebbe fare qualcosa di simile

public interface IXyzable { void xyz(); } 

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

Edit: Ora ho capito la domanda

+0

potresti fornirmi un codice funzionante per chiamare questa funzione di classe? – Elangesh

+0

Ho usato il seguente codice MyGenericClass myGenericClass = new MyGenericClass (); Console.WriteLine (myGenericClass.xyz()); Console.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

avrai bisogno di tutta la vostra possibile di di attuare alcune interfaccia in modo che si sa che obj.XYZ() ha un senso T, allora si può fare

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(); 
    } 
} 

Ho fatto MyGenericClass implementare Ixyz troppo dal momento che, ovviamente, esporre il metodo giusto, ma forse è meglio lasciare fuori in quanto permette

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

che è improbabile che sia mai una buona idea.

0

Si tratta di una tipica digitazione anatra, ma è possibile utilizzare la riflessione. Quando si crea la classe generica con un riferimento all'oggetto, utilizzare la riflessione per cercare e trovare un metodo con la firma corretta. Finché si memorizza un riferimento al metodo, le prestazioni non saranno eccessive.

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); 
    } 
} 

Naturalmente, si avrebbe bisogno di aggiungere molto di più per il controllo degli errori e così, ma questo è il succo di quello che si potrebbe fare. Inoltre, non dimenticare di aggiungere lo spazio dei nomi System.Reflection alla tua clausola using.

+0

perchè il down vote? Ho risposto alla domanda, no? Non consiglierei di farlo, ma risolve il suo problema: BaseGeneric . Xyz() chiama il metodo Xyz() dell'oggetto sottostante indipendentemente dal tipo. –

+0

La tua soluzione ha tutti i lati negativi della riflessione e non offre vantaggi della digitazione anatra. L'oggetto esterno (BaseGeneric) deve avere tutte le funzioni dichiarate su di esso. Se conosci queste funzioni, chiama la stessa funzione? –

+0

Memorizza nella cache il MethodInfo, quindi la riduzione delle prestazioni viene ridotta. Sembra l'oggetto sottostante - quindi cessa. Lo fa implementare di nuovo ogni metodo, quindi questo è il più grande svantaggio. Tuttavia, T potrebbe essere qualsiasi cosa che implementa Xyz, che è utile in alcuni scenari. –

1

Il sistema di tipo .NET non consente le dichiarazioni di tipo del modulo che si sta tentando. Uno dei motivi per cui ciò non è consentito dovrebbe essere intuitivo: come farebbe MyGenericClass<T> quando T è una classe sigillata (ad esempio System.String)?

Se è assolutamente necessaria questa funzionalità (e si sa che il tipo T da utilizzare non è sigillato), è possibile generare proxy in fase di runtime utilizzando le classi nello spazio dei nomi Reflection.Emit. Potrebbe anche essere possibile ottenere questo effetto utilizzando strumenti AOP come PostSharp.

+0

MyGenericClass produce un errore del compilatore. Se questa funzione linguistica fosse disponibile, l'ereditarietà da T vincolerebbe automaticamente T a essere non sigillato. Anche se questa è solo una parte del problema (vedi la mia risposta). –

4

La domanda specifica, perché non si può fare questo:

public class MyGenericClass<T> : T 

E si può fare questo:

public class MyGenericClass<T> 
{ 
    T obj; 
} 

La ragione è che il CLR piace essere in grado di compilare un singolo versione del codice per MyGenericClass che funzionerà per qualsiasi tipo di riferimento specificato per T.

Può farlo per il secondo caso, perché può tranquillamente sostituire T con object e inserire calchi del caso, più o meno equivalente a:

public class MyGenericClass 
{ 
    object obj; 
} 

Ma per la versione eredità, quel trucco non funziona.

Inoltre, molte strutture utili sarebbero impossibili da descrivere attraverso i vincoli di interfaccia. Quando si eredita da un tipo, si può fare molto di più che chiamare semplicemente i metodi su di esso - è anche possibile sovrascriverli. Considerate questo esempio ipotetico:

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

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

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

Quello che voglio fare c'è qualcosa come un "mix-in", dove MyGenericDerived fornisce le definizioni per le funzioni virtuali in qualunque base di esso viene applicato. Ma come fa il compilatore a sapere che T avrà un metodo chiamato MyVirtual che può essere sovrascritto? Avrei bisogno di mettere un limite su T. Come potrei esprimerlo attraverso le interfacce? È impossibile. Utilizzare le interfacce per descrivere i vincoli non è una soluzione adeguata una volta che si consente l'ereditarietà dei parametri di tipo. Quindi questa è un'altra ragione per cui oggi non esiste nella lingua.

0

Che dire di questo:

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; 
    } 
} 

questo modo si ottiene ciò che si vuole fare?

+0

Io non la penso così. Vuole che GenericClass esponga tutti i metodi di T senza ri-implementare nulla. Almeno, questa è la mia ipotesi migliore su ciò che sta chiedendo. –