260

Is there a particular reason why a generic ICloneable<T> does not exist?

It would be much more comfortable, if I would not need to cast it everytime I clone something.

ulrichb
  • 19,610
  • 8
  • 73
  • 87
Bluenuance
  • 4,813
  • 4
  • 23
  • 19
  • 7
    No! with all due respect to the 'reasons', I agree with you, they should have implemented it! – Shimmy Weitzhandler Jan 13 '10 at 00:53
  • It would have been a nice thing for Microsoft to have defined (the problem with brew-your-own interfaces is that interfaces in two different assemblies will be incompatible, even if they're semantically identical). Were I designing the interface, it would have three members, Clone, Self, and CloneIfMutable, all of which would return a T (the last member would either return Clone or Self, as appropriate). The Self member would make it possible to accept an ICloneable(of Foo) as a parameter and then use it as a Foo, without need for a typecast. – supercat Jan 12 '11 at 17:17
  • That would allow for a proper cloning class hierarchy, where inheritable classes expose a protected "clone" method, and have sealed derivatives that expose a public one. For example, one could have Pile, CloneablePile:Pile, EnhancedPile:Pile, and CloneableEnhancedPile:EnhancedPile, none of which would be broken if cloned (even though not all expose a public cloning method), and FurtherEnhancedPile:EnhancedPile (which would be broken if cloned, but doesn't expose any cloning method). A routine that accepts an ICloneable(of Pile) could accept a CloneablePile or a CloneableEnhancedPile... – supercat Jan 12 '11 at 17:26
  • ...even though CloneableEnhancedPile does not inherit from CloneablePile. Note that if EnhancedPile inherited from CloneablePile, FurtherEnhancedPile would have to expose a public cloning method and could be passed to code that would expect to Clone it, violating the Liskov Substitutability Principle. Since CloneableEnhancedPile would implement ICloneable(Of EnhancedPile) and by implication ICloneable(Of Pile), it could be passed to a routine expecting a cloneable derivative of Pile. – supercat Jan 12 '11 at 17:30

8 Answers8

155

In addition to Andrey's reply (which I agree with, +1) - when ICloneable is done, you can also choose explicit implementation to make the public Clone() return a typed object:

public Foo Clone() { /* your code */ }
object ICloneable.Clone() {return Clone();}

Of course there is a second issue with a generic ICloneable<T> - inheritance.

If I have:

public class Foo {}
public class Bar : Foo {}

And I implemented ICloneable<T>, then do I implement ICloneable<Foo>? ICloneable<Bar>? You quickly start implementing a lot of identical interfaces... Compare to a cast... and is it really so bad?

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 12
    +1 I always thought that the covariance problem was the real reason – Tamas Czinege Feb 11 '09 at 11:31
  • There is a problem with this: the explicit interface implementation must be _private_, which would cause problems should Foo at some point need to be cast to ICloneable... Am I missing something here? – Joel in Gö Mar 26 '09 at 10:33
  • 3
    My mistake: it turns out that, despite being defined as private, the method _will_ be called should Foo be cast to IClonable (CLR via C# 2nd Ed, p.319). Seems like an odd design decision, but there it is. So Foo.Clone() gives the first method, and ((ICloneable) Foo).Clone() gives the second method. – Joel in Gö Mar 26 '09 at 12:51
  • 1
    Actually, explicit interface implementations are, strictly speaking, part of the public API. In that they are callable publicly via casting. – Marc Gravell Mar 26 '09 at 12:58
  • Yes. Has a bad smell though, IMHO: methods that are declared private should be private, dammit. – Joel in Gö Mar 26 '09 at 13:18
  • From 20.4.1: Explicit interface member implementations have different accessibility characteristics than other members. Because explicit interface member implementations are never accessible through a qualified interface member name in a method invocation or a property access, they are in a sense... – Marc Gravell Mar 26 '09 at 13:29
  • ...private. However, since they can be accessed through an interface instance, they are in a sense also public. – Marc Gravell Mar 26 '09 at 13:29
  • QED ;) (why min 10 character for a comment?) – Joel in Gö Mar 26 '09 at 13:41
  • 9
    The proposed solution seems great at first... until you realize that in a class hierarchy, you want 'public Foo Clone()' to be virtual and overridden in derived classes so they can return their own type (and clone their own fields of course). Sadly, you can't change the return type in an override (the covariance problem mentioned). So, you come full circle back to the original problem again - the explicit implementation doesn't really buy you much (other than returning the base type of your hierarchy instead of 'object'), and you're back to casting most of your Clone() call results. Yuck! – Ken Beckett Apr 23 '12 at 03:11
  • In regards to your answers, on the line object ICloneable.Clone() {return Clone();}, how is it that Foo Clone() would be called, and not ICloneable.Clone() recursively? – Bruno Santos May 03 '15 at 16:11
  • @Bruno because : explicit interface implementation – Marc Gravell May 03 '15 at 19:15
123

ICloneable is considered a bad API now, since it does not specify whether the result is a deep or a shallow copy. I think this is why they do not improve this interface.

You can probably do a typed cloning extension method, but I think it would require a different name since extension methods have less priority than original ones.

Andrey Shchekin
  • 21,101
  • 19
  • 94
  • 162
  • 12
    I disagree, bad or not bad, it's very useful sometime for SHALLOW clonning, and in those cases is really needed the Clone, to save an unnecessary boxing and unboxing. – Shimmy Weitzhandler Jan 13 '10 at 00:51
  • @Merlyn I think it should be a separate question. One answer may be BinaryFormatter Serialize/Deserialize for deep cloning, but it really depends on task, required performance, etc. – Andrey Shchekin Jan 23 '11 at 10:22
  • What do you mean by _extension methods have less priority than original ones._ – Royi Namir Jul 22 '12 at 10:55
  • 2
    @AndreyShchekin: What's unclear about deep vs shallow cloning? If `List` had a clone method, I would expect it to yield a `List` whose items have the same identities as those in the original list, but I would expect that any internal data structures would be duplicated as needed to ensure that nothing done to one list will affect the *identities* of items stored in the other. Where's the ambiguity? A bigger problem with cloning comes with a variation of the "diamond problem": if `CloneableFoo` inherits from [not publicly cloneable] `Foo`, should `CloneableDerivedFoo` derive from... – supercat Aug 10 '12 at 15:26
  • @AndreyShchekin: `CloneableFoo` or from [not publicly cloneable] `DerivedFoo`? I would suggest that a generic `ICloneable` could resolve that issue if it derives from `ISelf` which contains a `Self` property of type `T` that simply returns itself. In that case, someone needing a cloneable `DerivedFoo` could accept a parameter of type `ICloneable`. – supercat Aug 10 '12 at 15:28
  • 4
    @supercat: I can not say I understand your expectation fully, as what will you consider an `identity` of the list itself, for example (in case of list of lists)? However, ignoring that, your expectation is not the only possible idea people may have when calling or implementing `Clone`. What if library authors implementing some other list do not follow your expectation? The API should be trivially unambiguous, not arguably unambiguous. – Andrey Shchekin Aug 11 '12 at 01:11
  • @AndreyShchekin: Suppose an automobile repair shop has a list of all cars that are in for service at any given moment. Such a list would be mutable. Someone is asked to take a "snapshot" of the list of cars in the shop at the some particular moment. Writing "the whiteboard in the shop" on a slip of paper (making a duplicate reference to the list) would clearly not suffice, since the next time the list is changed it would no longer represent a list of cars that *had been* in the shop when the snapshot was supposed to be taken. On the other hand, ... – supercat Aug 13 '12 at 14:50
  • @AndreyShchekin: ...someone asked to make a snapshot of the list would not be expected to manufacture duplicates of all the cars thereon. The cars themselves are mutable objects, with many mutable properties, though not all properies are mutable. The make and model, for example, would be immutable, so a snapshot of the list would capture the make and model of the cars left overnight. One would not expect the duplicate of the list to capture any mutable properties (e.g. odometer reading), however, unless the list itself contained explicit copies of them. – supercat Aug 13 '12 at 15:02
  • @AndreyShchekin: An important thing to note, though, is that making duplciate cars and writing down the VINs of those duplicate cars would not only require a lot of extra work--it would also be fundamentally *wrong*. Given daily lists of VINs, one could determine out how many times a particular car has stayed in the shop overnight. If every snapshot of the list contained the VINs of cars that were manufactured to match the cars that were brought in, however, such analysis would be impossible, since such a list would no longer record *the identity* of the cars that were brought in. – supercat Aug 13 '12 at 15:07
  • 3
    @supercat So you are talking about shallow copy. However, there is nothing fundamentally wrong with a deep copy, for example if you want to do a reversible transaction on in-memory objects. Your expectation is based on your use case, other people may have different expectations. If they put your objects into their objects (or vice versa), results will be unexpected. – Andrey Shchekin Aug 13 '12 at 22:23
  • @AndreyShchekin: The term "shallow copy" is sometimes used to refer to what I described, and sometimes used to refer to the result of `MemberwiseClone` on a class or copying a structure. While there are situations where deeper copying would be appropriate, such scenarios would entail a much tighter copying of the collection and its contents than would be implied by something like a `List`, and if one is going to that level one should go beyond `Clone`, using an interface with members `AsImmutable()` and `AsMutable()`; calling `AsImmutable` on an object should yield an immutable snapshot. – supercat Aug 13 '12 at 22:42
  • @AndreyShchekin: An immutable object is a snapshot of its own state, and could thus return itself. A mutable object should create an immutable snapshot and return that. If desired, it could cache that snapshot and, the next time `AsImmutable` is called, return the cached snapshot if it was still good. Even if the only way to tell whether the cached snapshot was still valid was to generate a new immutable object and compare it, returning the cached snapshot would expedite comparisons between it and the earlier one. A good weak interning collection could improve things even further. – supercat Aug 13 '12 at 22:45
  • @AndreyShchekin: Unconditional deep-cloning of mutable objects should IMHO be regarded as an anti-pattern. While aggressive copy-on-write approaches are not good for performance on multi-threaded systems, using shared immutable objects for the portion of a deep hierarchy which are held in common between instances can be a big win. – supercat Aug 13 '12 at 22:50
  • 7
    @supercat you do not take into account it is a part of .NET framework, not part of your application. so if you make a class that does not do deep cloning, then someone else makes a class that does do deep cloning and calls `Clone` on all its parts, it will not work predictably -- depending on whether that part was implemented by you or that person who likes deep cloning. your point about the patterns is valid but having IMHO in API is not clear enough -- it either should be called `ShallowCopy` to stress the point, or not provided at all. – Andrey Shchekin Aug 14 '12 at 00:36
  • @AndreyShchekin: If I had an object which implemented `IList` and `ICloneable`, and `T` was a class type, I would expect that cloning should give me a new list which held references to the same object instances as the original. I would regard a clone function that did anything else as broken. For an object to clone deeper than its semantic contents is not "optional"--it is a breaking behavior. – supercat Aug 14 '12 at 13:10
  • @AndreyShchekin: I suppose perhaps the biggest problem is that Microsoft didn't simply specify that ICloneable should work in the only fashion that would be logical and useful in the general case (which is what I described), but I can't see any reason why it should be expected to work in any other way. Of course, that would hardly be the only case where Microsoft has been less than optimal in its semantic specifications. Object equality has the same issue. It's not hard to define an equivalence relation which would be unambiguously applicable to every single type of object, but... – supercat Aug 14 '12 at 16:36
  • ...Microsoft put a few quirks in a couple types' implementation of `Equals`. A proper equivalence relation would specify that two objects should compare "equal" if and only if they would be semantically indistinguishable except by checking reference equality. Having such an equivalence relation available for all classes would facilitate things like interning classes (given two objects compare equal, one of which is in an interning dictionary, one would be able to substitute the other safely). Too bad the `Object.Equals` overrides of `float`, `double`, and `Decimal` don't work that way. – supercat Aug 14 '12 at 16:40
  • 1
    FWIW I came to this question in search of a canonical method to clone a list such that I could alter properties of its members without altering the members in the original list. – Tim Sparkles Oct 20 '15 at 01:05
  • Lots of valid reasons why it's a bad idea. However, in the real world, you sometimes need it. For example, in .net Workflow Foundation, I need work with an object, modify it's content deep in some library code, and then give it back to WF. If it's the same reference, it won't detect changes :( so I have to make a copy of it, and a shallow copy is enough. – Andrei May 14 '20 at 17:56
19

I need to ask, what exactly would you do with the interface other than implement it? Interfaces are typically only useful when you cast to it (ie does this class support 'IBar'), or have parameters or setters that take it (ie i take an 'IBar'). With ICloneable - we went through the entire Framework and failed to find a single usage anywhere that was something other than an implementation of it. We've also failed to find any usage in the 'real world' that also does something other than implement it (in the ~60,000 apps that we have access to).

Now if you would just like to enforce a pattern that you want your 'cloneable' objects to implement, that's a completely fine usage - and go ahead. You can also decide on exactly what "cloning" means to you (ie deep or shallow). However, in that case, there's no need for us (the BCL) to define it. We only define abstractions in the BCL when there is a need to exchange instances typed as that abstraction between unrelated libraries.

David Kean (BCL Team)

David Kean
  • 5,722
  • 26
  • 26
  • 2
    Non-generic ICloneable isn't very useful, but `ICloneable` could be quite useful if it inherited from `ISelf`, with a single method `Self` of type `T`. One doesn't often need "something that's cloneable", but one may very well need a `T` that's cloneable. If a cloneable object implements `ISelf`, a routine that needs a `T` that's cloneable can accept a parameter of type `ICloneable`, even if not all of the cloneable derivatives of `T` share a common ancestor. – supercat Mar 01 '12 at 00:30
  • Thanks. That's similar to cast situation I mentioned above (ie 'does this class support 'IBar'). Sadly, we've only come up with very limited and isolated scenarios where you would actually make use of the fact that T is cloneable. Do you have situations in mind? – David Kean Mar 01 '12 at 03:57
  • One thing that's sometimes awkward in .net is managing mutable collections when the contents of a collection are supposed to be viewed as a value (i.e. I will want to know later the set of items that are in the collection now). Something like `ICloneable` could be useful for that, though a broader framework for maintaining parallel mutable and immutable classes might be more helpful. In other words, code which needs to see what some type of `Foo` contains but is neither going to mutate it nor expect that it won't ever change could use an `IReadableFoo`, while... – supercat Mar 01 '12 at 05:18
  • ...code which wants to hold the contents of `Foo` could use an `ImmutableFoo` while code that to wants to manipulate it could use a `MutableFoo`. Code given any type of `IReadableFoo` should be able to get either a mutable or immutable version. Such a framework would be nice, but unfortunately I can't find any nice way to set things up in a generic fashion. If there were a consistent way to make a read-only wrapper for a class, such a thing could be used in combination with `ICloneable` to make an immutable copy of a class which holds `T`'. – supercat Mar 01 '12 at 05:24
  • @supercat If you're wanting to clone a `List`, such that the cloned `List` is a new collection holding pointers to all of the same objects in the original collection, there are two easy ways of doing that without `ICloneable`. The first is the `Enumerable.ToList()` extension method: `List clone = original.ToList();` The second is the `List` constructor that takes an `IEnumerable`: `List clone = new List(original);` I suspect the extension method is probably just calling the constructor, but both of these will do what you're requesting. ;) – CptRobby Oct 03 '13 at 17:54
  • @CptRobby: Given any `IEnumerable`, one can produce an immutable sequence from it by calling `ToList` and then wrapping that in a `ReadOnlyCollection` or otherwise ensuring it will never be exposed to anything that might mutate it. My complaints with that are (1) a `List` is just one kind of thing; there's no standard interface which would allow one to make an immutable copy of anything that implements the interface without having to know what it is; (2) "cloning" an instance which is already immutable by simply copying the reference can be many orders of magnitude more efficient... – supercat Oct 03 '13 at 18:17
  • ...than making a copy of its contents. Suppose, for example, that one has an `IEnumerable mySequence, and one wants `wasSequence` to refer to an object that will always return the sequence of items that `mySequence` returns right now. If `mySequence` is `Enumerable.Range(1,1000000)`, one could say `wasSequence=new ReadOnlyCollection(mySequence.ToList());` but copying the reference would be many orders of magnitude faster. – supercat Oct 03 '13 at 18:24
  • @supercat: I'm not disagreeing with you per se, but would like to point out that `ReadOnlyCollection` can only be constructed from an `IList`, so unless you want to use some other immutable collection wrapper, you're pretty much stuck with converting it to a `List` (or an array) first. I agree that it wouldn't make sense to clone an immutable collection, but again, I only know of `ReadOnlyCollection`, so it would be trivial to provide an explicit exclusion for that case. As for `Enumerable.Range()`, I had to look it up to see what it is, but... – CptRobby Oct 03 '13 at 19:52
  • ...from the description, it returns some unknown type that defers execution until it is enumerated. So the only thing we can say about it is that you can enumerate it because it implements `IEnumerable`, so there's no way of knowing whether it is mutable or not without trying to cast it to an `IList` or something like that and trying to change it. So the only thing you can do in that situation is to enumerate it into a list or array and create a `ReadOnlyCollection` from it, if you are wanting to ensure that you have an immutable collection. – CptRobby Oct 03 '13 at 20:01
  • Oh, and from just doing a quick search, it appears that there are a few other less used immutable collections `SynchronizedReadOnlyCollection`, `ReadOnlyObservableCollection`, and `ReadOnlyDictionary`. And it looks like BCL is working on adding more (hopefully they will all implement `IReadOnlyCollection` to easily type check them). I've only used `ReadOnlyCollection` on one occasion, so I don't claim to be an expert in that area. And again, I'm not debating you, I was just pointing out a simple solution to the scenario you pointed out. ;) – CptRobby Oct 03 '13 at 20:10
  • @CptRobby: My point was that the *lack* of standardized interfaces related to immutability means that there's often no alternative to making redundant copies of immutable data--a fact which can increase execution size and memory requirements by orders of magnitude. The indicated `Enumerable.Range`, btw, is an immutable object which encapsulates the sequence {1, 2, 3, 4,..., 9999999, 10000000}. Given that sequence, one could make an immutable object that encapsulates the same sequence by building a 10,000,000-item array but simply copying the reference is a *lot* cheaper. – supercat Oct 03 '13 at 23:30
  • @CptRobby: Mr. Kean wondered what use cloning would be, and I was trying to suggest that cloning in and of itself isn't necessarily useful, but it could be useful if there were also some support for immutability. If there existed an `IConvertibleToImmutable` with an `AsImmutable`, then types with immutable or partially-immutable backing stores could implement it in a manner more efficient than a straight-up clone. – supercat Oct 03 '13 at 23:33
  • @supercat: Again, I'm no expert on immutable collections or objects, but if I were using them, I would agree that it would be better to have some sort of flag on them to specify that they are immutable. Unfortunately, it appears that even `IReadOnlyCollection` fails in that regard since it is implemented on `List`! [facepalm] Regardless, all I was suggesting was a way to clone a list, without even mentioning mutability. Thanks for the discussion though. ;) – CptRobby Oct 04 '13 at 15:57
14

I think the question "why" is needless. There is a lot of interfaces/classes/etc... which is very usefull, but is not part of .NET Frameworku base library.

But, mainly you can do it yourself.

public interface ICloneable<T> : ICloneable {
    new T Clone();
}

public abstract class CloneableBase<T> : ICloneable<T> where T : CloneableBase<T> {
    public abstract T Clone();
    object ICloneable.Clone() => return this.Clone();
}

public abstract class CloneableExBase<T> : CloneableBase<T> where T : CloneableExBase<T> {
    protected abstract T CreateClone();
    protected abstract void FillClone(T clone);
    public override T Clone() {
        T clone = this.CreateClone();
        if (clone is null ) {
            throw new NullReferenceException( "Clone was not created." );
        }

        this.FillClone(clone);
        return clone
    }
}

public abstract class PersonBase<T> : CloneableExBase<T> where T : PersonBase<T> {
    public string Name { get; set; }

    protected override void FillClone( T clone ) {
        clone.Name = this.Name;
    }
}

public sealed class Person : PersonBase<Person> {
    protected override Person CreateClone() => return new Person();
}

public abstract class EmployeeBase<T> : PersonBase<T> where T : EmployeeBase<T> {
    public string Department { get; set; }

    protected override void FillClone(T clone) {
        base.FillClone(clone);

        clone.Department = this.Department;
    }
}

public sealed class Employee : EmployeeBase<Employee> {
    protected override Employee CreateClone() => return new Employee();
}
TcKs
  • 25,849
  • 11
  • 66
  • 104
  • 1
    Any workable clone method for an inheritable class must use Object.MemberwiseClone as a starting point (or else use reflection) since otherwise there's no guarantee that the clone will be the same type as the original object. I have a pretty nice pattern if you're interested. – supercat Oct 22 '10 at 22:25
  • @supercat why not make it an answer then? – nawfal Apr 17 '13 at 19:25
  • "There is a lot of interfaces/classes/etc... which is very usefull, but is not part of .NET Frameworku base library." Can you give us examples? – Krythic Dec 25 '16 at 01:52
  • 1
    @Krythic i.e.: advanced datastructures like b-tree, red-black tree, circle buffer. In '09 there was no tuples, generic weak-reference, concurrent collections ... – TcKs Dec 26 '16 at 16:14
12

It's pretty easy to write the interface yourself if you need it:

public interface ICloneable<T> : ICloneable
        where T : ICloneable<T>
{
    new T Clone();
}
Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
Mauricio Scheffer
  • 98,863
  • 23
  • 192
  • 275
  • I included a snippet since because of the honor of the copy-rights the link was broken... – Shimmy Weitzhandler Jan 12 '10 at 16:37
  • 2
    And how exactly is that interface supposed to work? For the result of a clone operation to be castable to type T, the object being cloned has to derive from T. There's no way to set up such a type constraint. Realistically speaking, the only thing I can see the result of iCloneable returning is a type iCloneable. – supercat Oct 16 '10 at 22:17
  • @supercat: yes, that's exactly what Clone() returns: a T which implements ICloneable. MbUnit has been using this interface for *years*, so yes, it works. As for the implementation, take a peek into MbUnit's source. – Mauricio Scheffer Oct 17 '10 at 02:14
  • 2
    @Mauricio Scheffer: I see what's going on. No type actually implements iCloneable(of T). Instead, each type implements iCloneable(of itself). That would work, I guess, though all it does is move a typecast. It's too bad there's no way to declare a field as having an inheritance constraint and an interface one; it would be helpful to have a cloning method return an object of a semi-cloneable (cloning exposed as Protected method only) base type, but with a cloneable type constraint. That would allow an object to accept cloneable derivatives of semi-cloneable derivatives of a base type. – supercat Oct 17 '10 at 15:25
  • @Mauricio Scheffer: BTW, I would suggest that ICloneable(of T) also support a readonly Self property (of return type T). This would allow a method to accept an ICloneable(of Foo) and use it (via the Self property) as a Foo. – supercat Dec 01 '10 at 00:56
10

Having read recently the article Why Copying an Object is a terrible thing to do?, I think this question needs additional clafirication. Other answers here provide good advices, but still the answer isn't complete - why no ICloneable<T>?

  1. Usage

    So, you have a class that implements it. While previously you had a method that wanted ICloneable, it now has to be generic to accept ICloneable<T>. You would need to edit it.

    Then, you could have got a method that checks if an object is ICloneable. What now? You can't do is ICloneable<> and as you don't know the type of the object at compile-type, you can't make the method generic. First real problem.

    So you need to have both ICloneable<T> and ICloneable, the former implementing the latter. Thus an implementer would need to implement both methods - object Clone() and T Clone(). No, thanks, we already have enough fun with IEnumerable.

    As already pointed out, there is also the complexity of inheritance. While covariance may seem to solve this problem, a derived type needs to implement ICloneable<T> of its own type, but there is already a method with the same signature (= parameters, basically) - the Clone() of the base class. Making your new clone method interface explicit is pointless, you will lose the advantage you sought when creating ICloneable<T>. So add the new keyword. But don't forget that you would also need to override the base class' Clone() (the implementation has to remain uniform for all derived classes, i.e. to return the same object from every clone method, so the base clone method has to be virtual)! But, unfortunately, you can't both override and new methods with the same signature. Choosing the first keyword, you'd lose the goal you wanted to have when adding ICloneable<T>. Chossing the second one, you'd break the interface itself, making methods that should do the same return different objects.

  2. Point

    You want ICloneable<T> for comfort, but comfort is not what interfaces are designed for, their meaning is (in general OOP) to unify the behavior of objects (although in C#, it is limited to unifying the outer behavior, e.g. the methods and properties, not their workings).

    If the first reason hasn't convinced you yet, you could object that ICloneable<T> could also work restrictively, to limit the type returned from the clone method. However, nasty programmer can implement ICloneable<T> where T is not the type that is implementing it. So, to achieve your restriction, you can add a nice constraint to the generic parameter:
    public interface ICloneable<T> : ICloneable where T : ICloneable<T>
    Certainly more restrictive that the one without where, you still can't restrict that T is the type that is implementing the interface (you can derive from ICloneable<T> of different type that implements it).

    You see, even this purpose couldn't be achieved (the original ICloneable also fails at this, no interface can truly limit the behavior of the implementing class).

As you can see, this proves making the generic interface is both hard to fully implement and also really unneeded and useless.

But back to the question, what you really seek is to have comfort when cloning an object. There are two ways to do it:

Additional methods

public class Base : ICloneable
{
    public Base Clone()
    {
        return this.CloneImpl() as Base;
    }

    object ICloneable.Clone()
    {
        return this.CloneImpl();
    }

    protected virtual object CloneImpl()
    {
        return new Base();
    }
}

public class Derived : Base
{
    public new Derived Clone()
    {
        return this.CloneImpl() as Derived;
    }

    protected override object CloneImpl()
    {
        return new Derived();
    }
}

This solution provides both comfort and intended behavior to users, but it's also too long to implement. If we didn't want to have the "comfortable" method returning the current type, it is much more easy to have just public virtual object Clone().

So let's see the "ultimate" solution - what in C# is really intented to give us comfort?

Extension methods!

public class Base : ICloneable
{
    public virtual object Clone()
    {
        return new Base();
    }
}

public class Derived : Base
{
    public override object Clone()
    {
        return new Derived();
    }
}

public static T Copy<T>(this T obj) where T : class, ICloneable
{
    return obj.Clone() as T;
}

It's named Copy not to collide with the current Clone methods (compiler prefers the type's own declared methods over extension ones). The class constraint is there for speed (doesn't require null check etc.).

I hope this clarifies the reason why not to make ICloneable<T>. However, it is recommended not to implement ICloneable at all.

IS4
  • 11,945
  • 2
  • 47
  • 86
  • **Appendix #1:** The only possible usage of a generic `ICloneable` is for value types, where it could circumvent the boxing of the Clone method, and it implies you have the value unboxed. And as structures can be cloned (shallowly) automatically, there is no need to implement it (unless you make it specific that it means deep copy). – IS4 Nov 12 '14 at 20:00
  • The extension method is genious! – Dmitry Avtonomov Jul 21 '23 at 18:49
1

A big problem is that they could not restrict T to be the same class. Fore example what would prevent you from doing this:

interface IClonable<T>
{
    T Clone();
}

class Dog : IClonable<JackRabbit>
{
    //not what you would expect, but possible
    JackRabbit Clone()
    {
        return new JackRabbit();
    }

}

They need a parameter restriction like:

interfact IClonable<T> where T : implementing_type
sheamus
  • 3,001
  • 4
  • 31
  • 54
  • 10
    That doesn't seem as bad as `class A : ICloneable { public object Clone() { return 1; } /* I can return whatever I want */ }` – Nikola Novak Jul 27 '12 at 20:23
  • 2
    I don't really see what the problem is. No interface can force implementations to behave reasonably. Even if `ICloneable` could constrain `T` to match its own type, that wouldn't force an implementation of `Clone()` to return anything remotely resembling the object upon which it was cloned. Further, I would suggest that if one is using interface covariance, it may be best to have classes which implement `ICloneable` be sealed, have the interface `ICloneable` include a `Self` property which is expected to return itself, and... – supercat Aug 27 '12 at 16:40
  • ...have consumers cast or constrain to `ICloneable` or `ICloneable>`. The `BaseType` in question should have a `protected` method for cloning, which would be called by the type which implements `ICloneable`. This design would allow for the possibility that one might wish to have a `Container`, a `CloneableContainer`, a `FancyContainer`, and a `CloneableFancyContainer`, the latter being usable in code which requires a cloneable derivative of `Container` or which requires a `FancyContainer` (but doesn't care if it's cloneable). – supercat Aug 27 '12 at 16:45
  • The reason I'd favor such a design is that the issue of whether a type can be cloned sensibly is somewhat orthogonal to other aspects of it. For example, one might have a `FancyList` type which could be cloned sensibly, but a derivative might automatically persist its state in a disk file (specified in the constructor). The derived type couldn't be cloned, because its state would be attached to that of a mutable singleton (the file), but that shouldn't preclude use of the derived type in places which need most features of a `FancyList` but wouldn't need to clone it. – supercat Aug 27 '12 at 16:56
  • +1 - this answer is the only one from those I've seen here that really answers the question. – IS4 Nov 12 '14 at 18:12
0

It's a very good question... You could make your own, though:

interface ICloneable<T> : ICloneable
{
  new T Clone ( );
}

Andrey says it's considered a bad API, but i have not heard anything about this interface becoming deprecated. And that would break tons of interfaces... The Clone method should perform a shallow copy. If the object also provides deep copy, an overloaded Clone ( bool deep ) can be used.

EDIT: Pattern i use for "cloning" an object, is passing a prototype in the constructor.

class C
{
  public C ( C prototype )
  {
    ...
  }
}

This removes any potential redundant code implementation situations. BTW, talking about the limitations of ICloneable, isn't it really up to the object itself to decide whether a shallow clone or deep clone, or even a partly shallow/partly deep clone, should be performed? Should we really care, as long as the object works as intended? In some occasions, a good Clone implementation might very well include both shallow and deep cloning.

baretta
  • 7,385
  • 1
  • 25
  • 25
  • "bad" does not mean deprecated. It simply mean "you're better off not using it". It's not deprecated in the sense that "we'll remove the ICloneable interface in the future". They just encourage you not to use it, and won't update it with generics or other new features. – jalf Feb 11 '09 at 11:22
  • Dennis: See Marc's answers. Covariance / inheritance issues make this interface pretty much unusable for any scenario that is at least marginally complicated. – Tamas Czinege Feb 11 '09 at 11:33
  • Yea, i can see the limitations of ICloneable, for sure... I rarely need to use cloning, though. – baretta Feb 11 '09 at 12:07