2012-06-25 10 views
16

possiamo specificare un "deriva da" vincolo sui parametri di tipo generico in questo modo:Esiste un vincolo di tipo generico per "dove NON viene derivato da"?

class Bar<T> where T : IFooGenerator 

C'è un modo per specificare NON derivati ​​da?


mio caso d'uso: Ho un sacco di FooGenerator s che sono parallelizzabile, con lo stesso codice di parallelizzazione per ciascuno, ma non li voglio sempre essere parallelizzati.

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

Così, ho creare una classe contenitore generico per la generazione di Foo in parallelo:

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

Dal momento che voglio FooGenerator e ParallelFooGenerator<FooGenerator> ad essere intercambiabili, faccio ParallelFooGenerator : IFooGenerator. Tuttavia, chiaramente non voglio che lo ParallelFooGenerator<ParallelFooGenerator> sia legale.

Quindi, come domanda ausiliaria, c'è forse un modo migliore per progettare questo se i vincoli "non derivati ​​da" sono impossibili?

+2

'ParallelFooGenerator ' già non è possibile, perché 'ParallelFooGenerator' è un tipo generico e non è stato specificato un argomento generico. Ad esempio, 'ParallelFooGenerator >' è possibile - e permetterebbe ad un tipo simile di essere così male? – cdhowie

+1

No non è possibile - restrizioni consentite: http://msdn.microsoft.com/en-us/library/d5x73970.aspx – Slugart

+0

@cdhowie: Wow, derp, hai ragione. Bene, questo risolve il mio problema :) Ma la domanda potrebbe ancora essere utile per gli altri! –

risposta

9

Si potrebbe usare qualcosa come il seguente:

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

Questo è un design migliore imho.* L'aggiunta di * un'interfaccia di livello superiore piuttosto che limitare eredacy di un livello è più pulita e più facile da capire. Ogni interfaccia e classe ha senso da sola. – vidstige

+0

@cdhowie ha risolto * il mio * problema, ma sto contrassegnando questo corretto in quanto risponde alla domanda nel titolo. Grazie! –

7

ParallelFooGenerator<ParallelFooGenerator> non è possibile, perché ParallelFooGenerator è un tipo generico e non è stato specificato un argomento generico.

Ad esempio, ParallelFooGenerator<ParallelFooGenerator<SomeFooGenerator>> è possibile - e consentirebbe ad un tipo di questo tipo di essere così male?

4

La semplice risposta è no.

La risposta lunga (ancora):

Microsoft mette bene nel loro explanation of type constrains: "Il compilatore deve avere qualche garanzia che l'operatore o il metodo di cui ha bisogno per chiamare saranno supportate da qualsiasi argomento di tipo che potrebbe essere specificato dal codice cliente. "

Lo scopo fondamentale dei vincoli non è quello di impedire l'utilizzo di determinati tipi, ma piuttosto di consentire al compilatore di sapere quali operatori o metodi sono supportati. È possibile, tuttavia, check if a type implements/inherits a specific interface/base class in fase di esecuzione e generare un'eccezione. Con ciò, però, non sarà possibile ottenere un errore in fase di progettazione da intellisense.

Spero che questo aiuti.

Problemi correlati