11

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()
    {
        ....
    }
}
Alex
  • 14,104
  • 11
  • 54
  • 77
sheamus
  • 3,001
  • 4
  • 31
  • 54

2 Answers2

9

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.

Jordão
  • 55,340
  • 13
  • 112
  • 144
  • You can enforce it at runtime, too. See Ben Voigt' answer. – usr Jul 19 '12 at 22:41
  • @usr: that won't work, only if you add the static constructor to the concrete classes themselves, which would be totally redundant. – Jordão Jul 19 '12 at 23:31
3

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).

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • The static ctor idea is great. – usr Jul 19 '12 at 22:41
  • -1 The static constructors would have to be defined in the concrete classes themselves, which would be totally redundant and unnecessary with the declaration of the self-type parameter itself. – Jordão Jul 19 '12 at 23:34
  • @Jordão: That's not true, reflection can discover all classes inheriting from the base class or implementing the interface. – Ben Voigt Jul 20 '12 at 02:47
  • @BenVoigt: OK, but that starts to be a little bit ... cumbersome. You'll have to look for all classes in all loaded assemblies if they inherit from you. And ... you can't add a static constructor to an interface in C#. – Jordão Jul 20 '12 at 02:49
  • @Jordão: I was thinking more of a base class. Interfaces can have type initializers in .NET (although the C# compiler doesn't help with that) but they don't run at a convenient time. But arranging for a piece of code to run isn't that difficult. And there's an event that runs when new assemblies are loaded. – Ben Voigt Jul 20 '12 at 02:51
  • True, and you could even use a module initializer. But still, it's not as trivial as your answer purports it to be... It takes a lot of non-trivial effort (look for all concrete subclasses and subscribe to an event that runs when assemblies are loaded). Add these bits of information and I'll be able to remove my downvote :-) – Jordão Jul 20 '12 at 02:55
  • Absolutely! I removed my downvote. I'm sorry to say that I won't upvote because I still think it's more trouble than it's worth.... – Jordão Jul 20 '12 at 03:16