Herencia en un parámetro de tipo genérico restringido

Sé que no es posible heredar de un parámetro de tipo genérico, pero sería útil cuando se implementa un proxy común para derivados de un tipo abstracto 🙂

¿Alguien sabe por qué esto no es posible?

Ejemplo C #:

abstract class Foo { public virtual void Bar() { // nop } } class FooProxy : TFoo where TFoo : Foo { public override void Bar() { // do some stuff before base.Bar(); // do some stuff after } } 

EDITAR: Un poco más de código para ilustrar un ejemplo de cómo esto podría ser utilizado. Considere los siguientes derivados de Foo:

 class FooX : Foo { public string X { get; set; } public override void Bar() { Console.WriteLine("Doing Bar X"); } } class FooY : Foo { public string Y { get; set; } public override void Bar() { Console.WriteLine("Doing Bar Y"); } } 

Y el código de llamada:

 FooProxy fooXProxy = new FooProxy(); fooXProxy.X = "test X"; fooXProxy.Bar(); FooProxy fooYProxy = new FooProxy(); fooYProxy.Y = "test Y"; fooYProxy.Bar(); 

El código en la anulación de FooProxy del método Bar () se reutilizará al usar FooX y FooY.

EDITAR: Revisado según la respuesta de Pete OHanlon: el método Bar () se hizo virtual.

Porque no puedes. Los generics no son plantillas. No debe pensar en ellos como plantillas C ++ y esperar el mismo comportamiento. Son conceptos fundamentalmente diferentes.

La especificación C # explícitamente prohíbe el uso de parámetros de tipo como clase base:

C # 3.0 Especificación del lenguaje: Tipo de parámetros (§4.5)

Un parámetro de tipo no puede utilizarse directamente para declarar una clase base (§10.2.4) o una interfaz (§13.1.3).

Actualizar:

Entiendo lo que quieres hacer y su uso. Este es un caso de uso tradicional de plantillas C ++. Específicamente, si esto fuera posible con los generics C #, cosas como la biblioteca Moq podrían beneficiarse de ello. El problema es que las plantillas C ++ son comstackciones de “buscar y reemplazar” en tiempo de comstackción, mientras que los generics C # son algo de tiempo de ejecución.

Para demostrar este hecho, para esta clase:

 class Test where T : class { // whatever contents it might have... } 

solo se emitirá una sola IL en tiempo de comstackción y en tiempo de ejecución, el comstackdor JIT generará un único código nativo para todos los parámetros de tipo de tipo de referencia. Esto no es como las plantillas de C ++ en absoluto, donde el código nativo se emitiría para cada T separado (está sujeto a la optimización, pero conceptualmente, son piezas de código completamente separadas).

No puede heredar de un parámetro de tipo genérico porque el tipo no se conoce en tiempo de comstackción, por lo que el comstackdor no puede determinar qué es la superclase. Me doy cuenta de que, a primera vista, el hecho de que el comstackdor pueda descifrar qué es parece sugerir que debería ser capaz de descifrar qué es T, pero las dos cosas son diferentes.

Además, tienes un problema de lógica en Bar. No puedes llamar a base.Bar porque es un tipo abstracto. Para corregir esto, tendría que cambiar su implementación en Foo a

 public virtual void Bar() {} 

Porque Foo es un tipo abstracto.

Si implementó Foo en una clase y luego lo usó en la plantilla, podría hacerlo.

También puede usar una interfaz para hacer lo que intenta hacer, creo.

Editar:

Pensándolo bien mirando tu código, no tiene sentido. Tendría que crear una clase base del tipo GENERIC , luego derivar de eso para lograr lo que está tratando de hacer. También tendría muchísimo más sentido …

 abstract class Foo { public virtual void Bar(); }