2009-04-14 11 views
8

Duplicar posible:
Why cannot C# generics derive from one of the generic type parameters like they can in C++ templates?herencia genérica en C#?

que puedo hacer

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

¿Cómo haría el segundo? si no puedo hacer eso, ¿cómo puedo hacer algo como

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

¿Cuál es su motivación para intentar hacer esto? –

+0

Espere el tipo dinámico en C# 4.0. –

Respuesta

9

Esto no es posible, ya que dependiendo de qué tipo es T, la interfaz pública de MyGenericClass cambiaría.

Si usted tiene un montón de diferentes clases que todos exponen la misma interfaz, se puede declarar MyGenericClass para exponer esa interfaz, y en la ejecución de todas las funciones delegar las llamadas a obj

+0

Pero en el segundo caso, donde se usa T para declarar un miembro, ese miembro podría ser público, y entonces la interfaz pública de MyGenericClass cambiaría dependiendo del tipo de T. –

+0

Solo el tipo de datos de la propiedad, que se maneja inherentemente por .net y genéricos. Mi punto era que todas las funciones y propiedades se agregarían y eliminarían si funcionaran de la manera que él quisiera, no sin un cambio de tipo de datos –

+0

Eso es circular: "inherentemente manejado por genéricos": ¿por qué no maneja inherentemente el caso que no funciona? t trabajo? :) –

4

usted podría hacer algo como

public interface IXyzable { void xyz(); } 

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

Editar: Ahora entiendo la pregunta

+0

¿podría proporcionarme un código de trabajo para llamar a esta función de clase? – Elangesh

+0

He utilizado el siguiente código MyGenericClass myGenericClass = new MyGenericClass (); Console.WriteLine (myGenericClass.xyz()); Console.ReadLine(); – Elangesh

+0

pago y envío http://stackoverflow.com/questions/3419176/how-to-use-the-where-keyword-inc-c-sharp-with-a-generic-interface-and-inherita –

0

que necesitará todo de poner en práctica alguna de las interfaces para que sepa que obj.XYZ() tiene sentido su posible T, entonces usted puede hacer

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

he hecho MyGenericClass implementan IXYZ demasiado ya que, obviamente, sí expone el método correcto, pero tal vez eso es mejor dejar a cabo, ya que permite

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

que es poco probable que sea siempre una buena idea.

0

Esto es más o menos pato-tipado, pero podrías usar el reflejo. Cuando crea la clase genérica con una referencia al obj, use la reflexión para intentar encontrar un método con la firma correcta. Mientras almacene una referencia al método, el rendimiento no será tan malo.

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

Por supuesto, sería necesario añadir mucho más por la comprobación de errores y tal, pero esa es la esencia de lo que se podía hacer. Además, no olvide agregar el espacio de nombres System.Reflection a su cláusula de uso.

+0

¿por qué el voto a la baja? Respondí la pregunta, ¿verdad? No recomendaría hacerlo, pero resuelve su problema: BaseGeneric .Xyz() llama al método Xyz() del objeto subyacente sin importar de qué tipo sea ese tipo. –

+0

Su solución tiene todas las desventajas de la reflexión, y no hay beneficios de la tipificación de pato. El objeto externo (BaseGeneric) debe tener todas las funciones declaradas en él. Si conoce esas funciones, solo llame a la misma función? –

+0

Almacena en caché MethodInfo, por lo que se reduce la penalización de rendimiento. Parece el objeto subyacente, por lo que grazna. Le hace implementar cada método una y otra vez, por lo que es el mayor inconveniente. Sin embargo, T podría ser cualquier cosa que implemente Xyz, que es útil en ciertos escenarios. –

1

El sistema de tipo .NET no permitirá declaraciones de tipo del formulario que está intentando. Una razón por la cual esto no se permite debe ser intuitiva: ¿cómo actuaría MyGenericClass<T> cuando T es una clase sellada (por ejemplo, System.String)?

Si realmente necesita esta funcionalidad (y sabe que el tipo T que va a utilizar no está sellado), puede generar proxies en tiempo de ejecución utilizando las clases en el espacio de nombres Reflection.Emit. También puede ser posible lograr este efecto utilizando herramientas de AOP como PostSharp.

+0

MyGenericClass produciría un error de compilación. Si esta característica de idioma estuviera disponible, heredar de T limitaría automáticamente T a ser abierto. Aunque esto es solo una parte del problema (ver mi respuesta). –

4

La pregunta específica, por qué no se puede hacer esto:

public class MyGenericClass<T> : T 

Y usted puede hacer esto:

public class MyGenericClass<T> 
{ 
    T obj; 
} 

La razón es que el CLR le gusta ser capaz de compilar una sola versión del código para MyGenericClass que funcionará para cualquier tipo de referencia especificado para T.

Puede hacer esto para el segundo caso, porque puede reemplazar silenciosamente T con object e inserte los moldes apropiados, más o menos equivalente a:

public class MyGenericClass 
{ 
    object obj; 
} 

Pero para la versión de la herencia, ese truco no funciona.

Además, muchas instalaciones útiles serían imposibles de describir a través de las limitaciones de la interfaz. Cuando hereda de un tipo, puede hacer mucho más que solo llamar a métodos; también puede anularlos. Considere este ejemplo hipotético:

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

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

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

Lo que yo quiero hacer hay algo así como una "mezcla en-", donde MyGenericDerived suministra las definiciones de las funciones virtuales en cualquier base de que se aplica a. Pero, ¿cómo sabe el compilador que T tendrá un método llamado MyVirtual que se puede anular? Tendría que poner una restricción en T. ¿Cómo podría expresar eso a través de las interfaces? Es imposible. El uso de interfaces para describir restricciones no es una solución adecuada una vez que permite la herencia de los parámetros de tipo. Esa es otra razón por la cual no existe en el lenguaje de hoy.

0

Qué tal esto:

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

Con ello se consigue lo que quiere hacer?

+0

No lo creo. Quiere que GenericClass exponga todos los métodos de T sin volver a implementar nada. Al menos, esa es mi mejor suposición acerca de lo que está preguntando. –