2010-10-11 15 views
7

Vorrei implementare una generica classe C# che si presenta più o meno come segue:Posso dire che un parametro di tipo C# deve essere solo un tipo di interfaccia?

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

Questo non riesce a causa C# solo consentirà tipi dopo la classe di base per essere interfacce, così la prossima provo questo:

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

Ma poi ho trovato che C# non consente questo tipo di vincolo di tipo. Sono consentiti solo where T : struct e where T : class.

Come si può stabilire che un parametro di tipo deve essere solo un tipo di interfaccia?

+3

cosa stai cercando di ottenere? Non riesco davvero a pensare a una situazione in cui un tale vincolo sarebbe necessario. – jalf

risposta

6

Fondamentalmente, non è possibile.

È possibile eseguire un comando su un'interfaccia specifica, ma non generale per tutte le interfacce. Quindi è possibile limitare ad IEnumerable, ad esempio, ma non a qualsiasi interfaccia.

Cosa ti serve comunque?

+0

Ho notato che tutte le classi derivate da Foobar finiscono per implementare T. Ho pensato che potrei forse far rispettare questo caso spostando gli "attrezzi Blah" dalle mie classi derivate sulla classe base Foobar. – pauldoo

0

Questo fallisce perché C# solo consentirà tipi dopo la classe di base per essere interfacce

Questo vincolo è dovuto alla mancanza di ereditarietà multipla in C#. L'ereditarietà multipla può essere approssimata dall'uso di interfacce perché i metodi di override sono espliciti. Allo stesso modo, una classe può estendere solo un'altra classe, ma può implementare più interfacce. Il trucco qui è che la classe di implementazione DEVE definire il corpo per un metodo, in modo che l'implementazione sia specifica su quale metodo viene chiamato.

L'utilizzo di dove limitare T può essere applicato a una classe oa più interfacce. Non è possibile limitare l'intervallo a più classi.

1

Credo che tu abbia frainteso il significato di where T : struct e where T : class.

Un generico type constraint simili significa che T deve essere un tipo valore o un tipo riferimento rispettivamente.

Tuttavia, lo scopo di un'interfaccia è quello di definire un contratto, che è un concetto totalmente diverso rispetto al tipo di valore vs tipo riferimento semantica.

Pertanto una restrizione come where T : interface non avrebbe senso.

Se volete saperne di più, vi suggerisco di leggere la Guida per programmatori C# su vincoli di tipo:

Constraints on Type Parameters (C# Programming Guide)

+0

Un vincolo come tipo di interfaccia avrebbe senso se esistessero funzionalità linguistiche che sarebbero utilizzabili su tali tipi e solo su tali tipi. Ad esempio, sarebbe molto utile se si potesse definire un 'Wrapper : T in cui T: interface (Foo)', con la semantica che la classe definisca un campo 'Foo' di tipo' T', e implementa esplicitamente ciascuno membro 'm' dell'interfaccia' T' facendolo invocare 'Foo.m'. Una tale struttura generale non sarebbe lavorabile con le classi, anche con il supporto CLR, ma potrebbe essere piuttosto utile con le interfacce se il CLR fornisse le funzionalità necessarie. – supercat

4

Il vero problema di questo codice è che siete ereditando da un parametro di tipo.

Cercando di compilare

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

sarà ancora fallire con: CS0689 errore: Non può derivare da 'T', perché si tratta di un parametro di tipo.

Penso che questo sia perfettamente ragionevole, almeno nel caso di classi astratte, e volevo anche questa funzione, ma il compilatore C# non ti consente di farlo.

+0

+1 per menzionare il nucleo del problema (derivato dai parametri di tipo). – Frank

Problemi correlati