Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restrict generic parameter on interface to subclass

The following is contrived, but bear with me:

interface Clonable<TSubClass>
{
    TSubClass Clone();
}

How can I restrict TSubClass to be of the implementing type?

i.e only let the implementor do this:

class Dog : Clonable<Dog>
{
    Dog Clone() 
    {
        ....
    }
}

Not this:

class BadDog : Clonable<Rabbit>
{
    Rabbit Clone()
    {
        ....
    }
}
like image 532
sheamus Avatar asked Jul 19 '12 21:07

sheamus


2 Answers

You can't enforce that at compile-time, because .NET generics don't have template specialization or duck typing.

You can, however, include a static constructor (type initializer) that uses reflection to assert the relationship at load time. Ok, C# doesn't allow you to put a static constructor on an interface (even though .NET does allow it), so you would need to use a module initializer or a function you call yourself. Also, you would need to search for types implementing the interface, including types that aren't loaded yet (you can subscribe to the Assembly.Load event to be notified of types loaded in the future).

like image 165
Ben Voigt Avatar answered Oct 21 '22 10:10

Ben Voigt


You can't enforce that, only through convention and documentation....

The convention for me would be to use something like TSelf.

interface ICloneable<TSelf> where TSelf : ICloneable<TSelf> { ... }

Also note that any non-concrete construct that implements or inherits this interface should pass the constraint through...

[Serializable]
abstract class SerializableCloneable<TSelf> : ICloneable<TSelf> 
  where TSelf : SerializableCloneable<TSelf> { ... }

Note: I've implemented this check in NRoles using the convention of calling your self-type parameter S.

like image 43
Jordão Avatar answered Oct 21 '22 10:10

Jordão