2

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(); }
}
leofun01
  • 125
  • 1
  • 9
  • 1
    Are you just looking for [sealed](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/sealed)? – John Wu May 22 '18 at 02:22
  • 1
    This feels like a XY Problem - https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem . **Why** do you want to do this? – mjwills May 22 '18 at 02:23
  • @John Wu, no, I don't want to make classes as sealed (in common case). @mjwills, I want to prevent this : `ICloneable[] array = new[] { new Class(), new Other() };` – leofun01 May 22 '18 at 02:32
  • 2
    @leofun01That doesn't answer _why_. That answers _what_. – ProgrammingLlama May 22 '18 at 02:47
  • 2
    So you're asking if it's possible for any class to implement an interface using only itself as a parameter? So `class Foo : ICloneable` wouldn't work, it *has* to be `class Foo : ICloneable`? – AustinWBryan May 22 '18 at 02:50
  • @AustinWBryan, yes, Exactly! – leofun01 May 22 '18 at 02:52
  • 1
    And do you plan on having more than one of these classes, like a `Foo : ICloneable`, `Bar : ICloneable`, etc? – AustinWBryan May 22 '18 at 02:54
  • @AustinWBryan, yes. I have many cloneable classes in my project. – leofun01 May 22 '18 at 02:55
  • 2
    @leofun01 - The language does not support this. You just have to be careful when implementing your classes. – Enigmativity May 22 '18 at 03:08
  • @Enigmativity, yeah, it looks like. – leofun01 May 22 '18 at 03:10
  • 2
    Since your `Class`, `Other` classes and `ICloneable` interface are public, then any developer can use it however he wants. You can tell user what your classes should do (describe interface), but you can't tell them how to implement it. Moreover, I personally still don't see any possible applicability of this functionality. – Yeldar Kurmangaliyev May 22 '18 at 03:10

1 Answers1

3

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.

AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
  • 1
    Because the point is to pass in a type parameter, but he's wanting to remove it all together, but I could be wrong in that – AustinWBryan May 22 '18 at 03:10
  • 1
    I don't think he wants to remove it completely. He wants to enforce the right one. – Enigmativity May 22 '18 at 04:15
  • 1
    I realized, which is why I removed that bit. It's weird, I feel like there should be a way to do that. – AustinWBryan May 22 '18 at 04:31
  • 1
    You can't subclass a `public class Other` from a `private class`... You get an error. See for example [SharpLab](https://sharplab.io/#v2:EYLgtghgzgLgpgJwD4AEAMACFBGA3AWACgiAHBASwDcJ4sAmDAYQBsB7AOzgmGbgHkYAC0QYA3hgC+RFAGZ6GAcIQYQTNp269FiIqKJTCQA=) – xanatos May 22 '18 at 07:35
  • @xanatos Thanks, forgot that. I figured it would be better for encapsulation. – AustinWBryan May 22 '18 at 07:51