2012-06-25 19 views
16

podemos especificar un "derivado de" restricción sobre los parámetros de tipo genérico como esto:¿Existe una restricción de tipo genérica para "where NOT derived from"?

class Bar<T> where T : IFooGenerator 

¿Hay una manera de especificar NO derivan de?


Mi caso de uso: Tengo un montón de FooGenerator s que son paralelizable, con el mismo código de paralelización para cada uno, pero no quiero que siempre ser parallelized.

public class FooGenerator : IFooGenerator 
{ 
    public Foo GenerateFoo() { ... } 
} 

Por lo tanto, puedo crear una clase de contenedor genérico para generar Foo en paralelo:

public class ParallelFooGenerator<T> : IFooGenerator where T : IFooGenerator 
{ 
    public Foo GenerateFoo() 
    { 
     //Call T.GenerateFoo() a bunch in parallel 
    } 
} 

Ya que quiero FooGenerator y ParallelFooGenerator<FooGenerator> ser intercambiables, hago ParallelFooGenerator : IFooGenerator. Sin embargo, claramente no quiero que ParallelFooGenerator<ParallelFooGenerator> sea legal.

Entonces, como pregunta auxiliar, ¿hay quizás una mejor manera de diseñar esto si las restricciones "no derivadas de" son imposibles?

+2

'ParallelFooGenerator ' ya no es posible, porque 'ParallelFooGenerator' es un tipo genérico y no se ha especificado un argumento genérico. Por ejemplo, 'ParallelFooGenerator >' es posible, ¿y permitir que ese tipo realmente sea tan malo? – cdhowie

+1

No, no es posible, restricciones permitidas: http://msdn.microsoft.com/en-us/library/d5x73970.aspx – Slugart

+0

@cdhowie: Wow, derp, tienes razón. Bueno, eso resuelve mi problema :) ¡Pero la pregunta aún podría ser útil para otros! –

Respuesta

9

Usted podría utilizar algo como lo siguiente:

public interface IFooGenerator 
{ 
    Foo GenerateFoo(); 
} 

interface ISerialFooGenerator : IFooGenerator { } 

interface IParallelFooGenerator : IFooGenerator { } 

public class FooGenerator : ISerialFooGenerator 
{ 
    public Foo GenerateFoo() 
    { 
     //TODO 
     return null; 
    } 
} 

public class ParallelFooGenerator<T> : IParallelFooGenerator 
    where T : ISerialFooGenerator, new() 
{ 
    public Foo GenerateFoo() 
    { 
     //TODO 
     return null; 
    } 
} 
+1

Este es un mejor diseño imho.* Agregar * una interfaz de un nivel arriba en lugar de restringir inheritage un nivel más abajo es mucho más limpio y fácil de entender. Cada interfaz y clase tiene sentido por sí misma. – vidstige

+0

@cdhowie resuelto * mi * problema, pero estoy marcando esto correctamente ya que responde a la pregunta en el título. ¡Gracias! –

7

ParallelFooGenerator<ParallelFooGenerator> ya no es posible, porque ParallelFooGenerator es un tipo genérico y no especificó un argumento genérico.

Por ejemplo, ParallelFooGenerator<ParallelFooGenerator<SomeFooGenerator>> es posible, ¿y permitiría que ese tipo realmente sea tan malo?

4

La respuesta simple es no.

La respuesta larga (todavía no):

Microsoft pone así en su explanation of type constrains: "El compilador debe tener alguna garantía de que el operador o el método que necesita para llamar serán apoyados por cualquier tipo de argumento que podría ser especificado por el código del cliente ".

El propósito fundamental de las restricciones no es prohibir el uso de ciertos tipos, sino permitir que el compilador sepa qué operadores o métodos son compatibles. Sin embargo, puede check if a type implements/inherits a specific interface/base class en tiempo de ejecución y lanzar una excepción. Con eso, sin embargo, no podrás obtener un error de Intellisense en tiempo de diseño.

Espero que esto ayude.

Cuestiones relacionadas