2012-04-04 5 views
7

Ich habe eine unelegante Lösung für das, was ich brauche, aber bin auf der Suche nach einer eleganten Lösung, um es zu ersetzen.generische ererbte Typ Einschränkung in C#

Der folgende Code nicht kompiliert, sondern stellt dar, was ich tun möchte.

interface IWebService 
{ 
} 

abstract class BaseClient<T> 
{ 
} 

class SpecializedClient : BaseClient<IWebService> 
{ 
} 

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

Wo die T in ClientHelper<T> jede Klasse, die BaseClient unabhängig von der Templat-Typ übergeben erstreckt

Die unelegant Lösung fand ich ist:

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

Der Grund dieser unelegant wird ist mein proje ct endet mit einer Klasse ähnlich der folgenden:

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

Der ganze Weg bis zur Basisklasse, die einen einzigen Typ dauert. Sind das einfach die Kosten für eine komplexe Vererbungsstruktur generischer Klassen oder gibt es eine einfachere Möglichkeit, dies zu tun, während Typeinschränkungen für die Vorlagen beibehalten werden?

Antwort

5

Ihre "unelegante" Lösung ist die richtige, wenn die öffentliche Schnittstelle von BaseClient ihren generischen Typparameter in irgendeiner Weise offen legt.

So BaseClient unter der Annahme nicht, wie Sie es definiert:

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

Dann T Teil des öffentlichen Schnittstelle Vertrages BaseClient ist und deshalb als Teil des öffentlichen Schnittstelle Vertrages ClientHelper (wiederum unter der Annahme, dass BaseClient<U> ist über die Schnittstelle von ClientHelper verfügbar).

Auf der anderen Seite nehmen wir an, es als Beispiel tatsächlich ist es ausdrückt:

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

In diesem Fall können Sie tun:

interface IBaseClient 
{ 
    //Nothing about T here 
} 

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

und ClientHelper wird:

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

Die Schnittstelle könnte für einen Teil davon funktionieren, da einige meiner Klassen 'T' nicht öffentlich zugänglich machen, sondern sie einfach intern verwenden. Ich nehme jede Vereinfachung, die ich bekommen kann, da es anfängt, unhandlich zu werden. – Foran

+0

Das vereinfachte alle Fälle, in denen ich 'Klasse ' habe, wo 'T' nie öffentlich ausgesetzt ist. Einfach, aber so offensichtlich, dass ich es nicht sehen konnte. :-) Es hat ungefähr die Hälfte der Typen ausgeschnitten, die weitergeleitet werden müssen. – Foran

+0

Kühl. Schön, dass es für dich geklappt hat. Sie können möglicherweise auch einige zusätzliche generische Parameter eliminieren, wenn Sie alle *** Operationen *** für ein gegebenes "T" (Methoden, Eigenschaften, Ereignisse und Felder) verallgemeinern können, die nicht typabhängig in Schnittstellen sind . –

0

Eine Option scheint zu sein:

interface IWebService 
{ 
} 

interface IClient<out T> 
{ 
} 

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

class SpecializedClient : BaseClient<IWebService> 
{ 
} 

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

Allerdings funktioniert das nur, wenn Sie BaseClient nur T zurückgibt und es nie akzeptiert.

Verwandte Themen