Reputation: 235
I have an interface :
public interface ICloneable<out T>
where T : ICloneable<T>
{
T Clone();
}
that should receive a type that implement this interface (as shown below).
And I can create a class that implement it :
public class Class : ICloneable<Class>
{
public Class Clone() { return (Class)MemberwiseClone(); }
}
Great !
But anyone can create a class that implement ICloneable<T> "wrong".
Does exist a way to prevent inheritance as shown below ? (2 examples)
public class Other : ICloneable<Class>
{
public Class Clone() { return new Class(); }
}
public class Other : Class, ICloneable<Class>
{
public Class Clone() { return (Other)MemberwiseClone(); }
}
And allow inheritance as shown below ? (any from 2 examples)
public class Other : ICloneable<Other>
{
public Other Clone() { return (Other)MemberwiseClone(); }
}
public class Other : Class, ICloneable<Other>
{
public Other Clone() { return (Other)MemberwiseClone(); }
}
Upvotes: 2
Views: 163
Reputation: 3326
You cannot overload a class, so:
public class Other : Class {}
public class Other : Class, IC<Other> {}
Will never work.
Now, I'm gonna pull a Jon Skeet and show how you could do this, but then discourage you from doing it. You could do something like this:
public class CloneableOther : Class, ICloneable<Other> { }
public class Other : CloneableOther
{
}
public class CloneableFoo : Class, ICloneable<Foo> { }
public class Foo : CloneableFoo
{
}
What this code is doing is effectively removing the generic parameter from the inheritance. Except, Foo
can still do this: Foo : CloneableFoo, ICloneable<Other>
, and now you'll have to create two classes for every ICloneable
instance.
This goes into that why do you need this in the first place? It is a practice to do Foo : IInterface<Foo>
, but there's no way to enforce it. Your best bet is to just do copy and paste and just be sure that the class matches.
Maybe another way is to have in the constructor of Class
, a check to see if the type of ICloneable
is the type of the class, and to throw an exception if it isn't, and that could sort've feel like a compile time error, if it's done earlier enough in the runtime.
Upvotes: 3