2012-04-04 13 views
7

Ho una soluzione poco elegante per quello che mi serve, ma sono alla ricerca di una soluzione elegante per sostituirla.Restrizione di tipo ereditato generico in C#

Il seguente codice non viene compilato, ma rappresenta ciò che vorrei fare:.

interface IWebService 
{ 
} 

abstract class BaseClient<T> 
{ 
} 

class SpecializedClient : BaseClient<IWebService> 
{ 
} 

class ClientHelper<T> where T : BaseClient<*> 
{ 
} 

Qualora la T in ClientHelper<T> è ogni classe che estende BaseClient indipendentemente dal tipo su modelli passato in

La soluzione poco elegante che ho trovato è:

class ClientHelper<T, U> where T : BaseClient<U> {} 

La ragione per questo diventa poco elegante è il mio proge ct termina con una classe simile a:

class MyClass<A, B, C, D, E, F, G> where A : MyBaseClass<B, C, D, E, F, G> 

Tutto il percorso fino alla classe base che accetta un singolo tipo. È semplicemente il costo di avere un albero di ereditarietà complesso di classi generiche o esiste un modo più semplice per farlo mantenendo le restrizioni di tipo sui tipi di modelli?

risposta

5

La soluzione "inelegante" è quella giusta se l'interfaccia pubblica di BaseClient espone il suo parametro di tipo generico in alcun modo.

Quindi, supponendo BaseClient è non come definito che:

abstract class BaseClient<T> 
{ 
    //Something about T here 
} 

Poi T è parte del contratto interfaccia pubblica di BaseClient, e quindi parte del contratto interfaccia pubblica di ClientHelper (ancora una volta, partendo dal presupposto che BaseClient<U> viene esposto tramite l'interfaccia di ClientHelper).

D'altra parte, supponiamo che in realtà è come il tuo esempio dice:

abstract class BaseClient<T> 
{ 
    //Nothing about T here 
} 

In questo caso, si può fare:

interface IBaseClient 
{ 
    //Nothing about T here 
} 

abstract class BaseClient<T> : IBaseClient 
{ 
    // Whatever you like here 
} 

e ClientHelper diventa:

class ClientHelper<T> where T : IBaseClient 
{ 
} 
+0

L'interfaccia potrebbe funzionare per una parte di esso in quanto alcune delle mie classi non espongono pubblicamente "T" semplicemente lo utilizzano internamente. Prenderò ogni semplificazione che posso ottenere dal momento che sta iniziando a diventare poco maneggevole. – Foran

+0

Ciò semplifica tutti i casi in cui ho "Classe " dove "T" non è mai esposto pubblicamente. Semplice, eppure così ovvio che non potevo vederlo. :-) Ha tagliato circa la metà dei tipi che devono essere inoltrati. – Foran

+0

Freddo. Sono contento che ha funzionato per te. Potresti anche essere in grado di eliminare alcuni parametri generici aggiuntivi se puoi generalizzare tutte le operazioni *** *** per un dato 'T' (metodi, proprietà, eventi e campi) che non sono dipendenti dal tipo nelle interfacce . –

0

Un'opzione sembra essere:

interface IWebService 
{ 
} 

interface IClient<out T> 
{ 
} 

abstract class BaseClient<T> : IClient<T> 
{ 
} 

class SpecializedClient : BaseClient<IWebService> 
{ 
} 

class ClientHelper<T> where T : IClient<object> 
{ 
} 

Tuttavia ciò funzionerà solo se si BaseClient restituisce solo T e non lo accetta mai.