Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Self generic type

Tags:

c#

I'm building the following class:

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

What I need is to make T be the type of child Foo class:

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

Is it achievable? If so, how?

like image 214
Sergey Metlov Avatar asked Feb 25 '14 11:02

Sergey Metlov


People also ask

What is generic type?

A generic type is a generic class or interface that is parameterized over types. The following Box class will be modified to demonstrate the concept.

What does it mean for a class to be generic?

Generic classes encapsulate operations that are not specific to a particular data type. The most common use for generic classes is with collections like linked lists, hash tables, stacks, queues, trees, and so on.

Which character is used for generic type?

The question mark ( ? ) wildcard character can be used to represent an unknown type using generic code. Wildcards can be used with parameters, fields, local variables, and return types.


2 Answers

Something like a self-constraint will allow you to expose derived types and also constrain at the same time:

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

Then derived types define themselves as the target:

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

Please note though that this design tends to only have a small set of uses. Also, you lose the ability to refer to Foo as a base without specifying it's generic type.

There is also a blog post from Eric Lippert about how it is possible to abuse this design, so you might want to consider what it is you are actually trying to achieve by wanting to have your protected method reference the derived class directly.

You may be better off using interfaces to encapsulate the behaviour you are trying to achieve.

like image 193
Adam Houldsworth Avatar answered Sep 24 '22 10:09

Adam Houldsworth


You mean this:

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)
    {
    }
}

It would be easier to implement with an interface:

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>
{
}
like image 31
Patrick Hofman Avatar answered Sep 25 '22 10:09

Patrick Hofman