2010-10-11 24 views
7

me gustaría implementar una clase genérica de C# que se ve más o menos como sigue:¿Puedo indicar que un parámetro de tipo C# solo debe ser un tipo de interfaz?

abstract class Foobar<T> : AbstractBase, T 
{ ... } 

Esta falla debido a que C# sólo permitirá tipos después de la clase base sean las interfaces, así que la próxima que este intento:

abstract class Foobar<T> : AbstractBase, T where T : interface 
{ ... } 

Pero luego me parece que C# no permite esta forma de restricción de tipo. Solo se permiten where T : struct y where T : class.

¿Cómo puedo indicar que un parámetro de tipo solo debe ser un tipo de interfaz?

+3

¿Qué estás tratando de lograr? Realmente no puedo pensar en una situación donde tal restricción sería necesaria. – jalf

Respuesta

6

Básicamente, no se puede.

Puede hacer contstraint para una interfaz específica, pero no general para todas las interfaces. Por lo tanto, puede restringir a IEnumerable, por ejemplo, pero no a ninguna interfaz.

¿Para qué necesita esto de todos modos?

+0

Observé que todas las clases derivadas de Foobar también terminan implementando T. Pensé que podría hacer cumplir este caso moviendo los 'implementos Blah' de mis clases derivadas a la clase base Foobar. – pauldoo

0

esto no funciona debido a que C# sólo permitirá tipos después de la clase base sean las interfaces

Esta restricción se debe a la falta de herencia múltiple en C#. La herencia múltiple se puede aproximar mediante el uso de interfaces porque los métodos de anulación son explícitos. De la misma forma que una clase solo puede extender otra clase, pero puede implementar múltiples interfaces. El truco aquí es que la clase implementadora DEBE definir el cuerpo para un método, de modo que la implementación sea específica sobre qué método se llama.

El uso de un límite de donde T se puede aplicar a una clase, o varias interfaces. No puedes limitar el rango a varias clases.

1

Creo que malinterpretas el significado de where T : struct y where T : class.

Un genérico type constraint como esto significa que T debe haber un valor de tipo de o un tipo referencia respectivamente.

Sin embargo, el propósito de una interfaz es definir un contrato, que es un concepto totalmente diferente en comparación con tipo de valor vs. semántica de tipo de referencia. Por ejemplo, una restricción como where T : interface no tendría sentido.

Si usted quiere saber más, yo te sugiero leer la Guía de programación de C# en restricciones de tipo:

Constraints on Type Parameters (C# Programming Guide)

+0

Una restricción como tipo de interfaz tendría sentido si hubiera funciones de idioma que podrían utilizarse en dichos tipos y solo en dichos tipos. Por ejemplo, sería muy útil si se pudiera definir un 'Contenedor : T donde T: interfaz (Foo)', con la semántica que la clase definiría un campo 'Foo' de tipo' T', e implementar explícitamente cada miembro 'm' de la interfaz' T' haciendo que invoque 'Foo.m'. Tal facilidad general no sería factible con las clases, incluso con soporte CLR, pero podría ser bastante útil con las interfaces si el CLR proporcionara las características necesarias. – supercat

4

El verdadero problema de que el código es que son heredando de un parámetro de tipo.

intentar compilar

abstract class Foobar<T> : T { ... } 

todavía fallará con: CS0689 de error: No se puede derivar de 'T', ya que es un parámetro de tipo.

Creo que esto sería perfectamente razonable al menos en el caso de las clases abstractas, y yo también quería esta característica, pero el compilador de C# simplemente no te deja hacer eso.

+0

+1 para mencionar el núcleo del problema (derivado de los parámetros de tipo). – Frank

Cuestiones relacionadas