Coder Perfect

Why no ICloneable?

Problem

Is there a specific reason why there isn’t a generic ICloneableT>?

It would be a lot easier if I didn’t have to cast it every time I cloned something.

Asked by Bluenuance

Solution #1

In addition to Andrey’s response (which I agree with, +1), you may pick explicit implementation to make the public Clone() produce a typed object after ICloneable is finished:

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

Of course, a generic ICloneableT> has a second problem: inheritance.

If I have:

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

Do I implement ICloneableFoo> now that I’ve implemented ICloneableT>? ICloneable? You immediately begin to implement a slew of similar interfaces… When compared to a cast, is it really so bad?

Answered by Marc Gravell

Solution #2

Because it does not define whether the result is a deep or shallow copy, ICloneable is now deemed a poor API. This, I believe, is why they haven’t improved the interface.

You could certainly create a typed cloning extension method, but I believe it would need a different name because extension methods are given lower priority than original methods.

Answered by Andrey Shchekin

Solution #3

I have to wonder, if you weren’t going to implement the interface, what would you do with it? Interfaces are usually only helpful if you cast to them (e.g., does this class support ‘IBar’) or if you have parameters or setters that accept them (e.g., I take a ‘IBar’). When it came to ICloneable, we looked across the entire Framework and couldn’t identify a single use that wasn’t an implementation of it. We’ve also been unable to discover any application in the’real world’ that does more than implement it (out of the 60,000 apps we have access to).

Now, if you only want to enforce a pattern that your ‘cloneable’ objects should follow, that’s just great – and go ahead. You can also choose your own definition of “cloning” (ie deep or shallow). However, there is no need for us (the BCL) to define it in that instance. Only when there is a need to interchange instances typed as that abstraction between unrelated libraries can we establish abstractions in the BCL.

David Kean is a British actor (BCL Team)

Answered by David Kean

Solution #4

I don’t believe the enquiry “why” is necessary. There are many important interfaces/classes/etc. that are not included in the.NET Framework base library.

But, for the most part, 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();
}

Answered by TcKs

Solution #5

If you require an interface, it’s rather simple to write one yourself:

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

Answered by Mauricio Scheffer

Post is based on https://stackoverflow.com/questions/536349/why-no-icloneablet