2014-02-25 6 views
6

Ich baue die folgende Klasse:Selbstgenerischer Typ

abstract class Foo 
{ 
    protected abstract void Process(FooProcessor<T> processor) 
} 

Was ich brauche, ist zu T die Art der Kinder Foo Klasse zu machen sein:

class FooChild : Foo 
{ 
    protected override void Process(FooProcessor<FooChild> processor) 
    { 
    } 
} 

Ist es erreichbar? Wenn das so ist, wie?

Antwort

6

So etwas wie eine Selbstbeschränkung ermöglicht es Ihnen, abgeleitete Typen zu belichten und auch zugleich einschränken:

abstract class Foo<T> where T : Foo<T> 
{ 
    protected abstract void Process(FooProcessor<T> processor); 
} 

Dann abgeleitete Typen definieren sich als Ziel:

class FooChild : Foo<FooChild> 
{ 
    protected override void Process(FooProcessor<FooChild> processor) 
    { 
    } 
} 

Bitte beachten obwohl dieses Design dazu neigt, nur eine kleine Reihe von Verwendungen zu haben. Außerdem verlieren Sie die Möglichkeit, auf Foo als Basis zu verweisen, ohne seinen generischen Typ anzugeben.

Es gibt auch eine blog post from Eric Lippert darüber, wie es möglich ist, dieses Design zu missbrauchen, also sollten Sie überlegen, was Sie tatsächlich erreichen wollen, indem Sie möchten, dass Ihre geschützte Methode direkt auf die abgeleitete Klasse verweist.

Sie können besser mit den Schnittstellen arbeiten, um das Verhalten einzukapseln, das Sie erreichen möchten.

+0

In diesem Fall Kind chass Unterschrift ziemlich seltsam ist .. –

+0

Ich glaube nicht, seine möglich , weil Foo generisch ist - es gibt keine nicht-generische Foo-Klasse –

+0

@SergeyMetlov Ich habe diesen Ansatz schon einmal gesehen, um einen stark typisierten Verweis auf eine abgeleitete Klasse von einem Basistyp aus verfügbar zu machen, es fühlt sich immer etwas rückwärts an und ehrlich zu sein, habe ich nicht persönlich gebraucht um diesen Ansatz zu verwenden. –

1

Sie dies bedeuten:

class FooProcessor<T> 
{ 
} 

abstract class Foo<T> 
{ 
    protected abstract void Process(FooProcessor<T> processor); 
} 

class FooChild : Foo<FooChild> 
{ 
    protected override void Process(FooProcessor<FooChild> processor) 
    { 
    } 
} 

Es wäre einfacher, mit einer Schnittstelle zu implementieren:

interface FooProcessor<T> 
{ 
} 

interface Foo<T> 
{ 
    void Process(FooProcessor<T> processor); 
} 

class FooChild : Foo<FooChild> 
{ 
    void Foo<FooChild>.Process(FooProcessor<FooChild> processor) 
    { 
     this.Process((FooProcessorFooChild)processor); 
    } 

    protected void Process(FooProcessorFooChild processor) 
    { 
    } 
} 

class FooProcessorFooChild : FooProcessor<FooChild> 
{ 
} 
+0

'FooChild: Foo ' das ist ziemlich seltsam .. Gibt es eine Möglichkeit, solche verwirrende Signatur zu vermeiden? –

+0

@SergeyMetlov: Ist die zweite besser? Hinweis Ich persönlich würde die erste bevorzugen. –

+0

Das selbe wie für mich. Noch komplexer. –