通用ICloneable<T>不存在是否有特殊原因?

如果我不需要每次克隆时都强制施放它,那就舒服多了。


当前回答

ICloneable现在被认为是一个糟糕的API,因为它没有指定结果是深度复制还是浅复制。我认为这就是为什么他们不改进这个界面的原因。

您可能可以使用类型化克隆扩展方法,但我认为它需要一个不同的名称,因为扩展方法的优先级比原始方法低。

其他回答

ICloneable现在被认为是一个糟糕的API,因为它没有指定结果是深度复制还是浅复制。我认为这就是为什么他们不改进这个界面的原因。

您可能可以使用类型化克隆扩展方法,但我认为它需要一个不同的名称,因为扩展方法的优先级比原始方法低。

如果你需要的话,自己编写接口是很容易的:

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

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

现在,如果你只是想强制一个你想要你的“可克隆”对象实现的模式,这是一个完全好的用法——去吧。你也可以决定“克隆”对你来说到底意味着什么(即深度克隆还是浅克隆)。然而,在这种情况下,我们(BCL)不需要定义它。只有当需要在不相关的库之间交换抽象类型的实例时,我们才在BCL中定义抽象。

大卫·基恩(BCL队)

我认为“为什么”这个问题是不必要的。有很多接口/类等…它非常有用,但不是. net Frameworku基础库的一部分。

但是,主要是你可以自己做。

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();
}

最近我读了一篇文章《为什么复制对象是一件可怕的事情?》我认为这个问题需要进一步澄清。这里的其他答案提供了很好的建议,但答案仍然不完整——为什么没有ICloneable<T>?

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

正如您所看到的,这证明了通用接口很难完全实现,而且真的不需要和无用。

但回到问题上,你真正寻求的是克隆对象时的舒适感。有两种方法:

额外的方法

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();
    }
}

这个解决方案为用户提供了舒适和预期的行为,但是实现起来太长了。如果我们不想使用“舒服的”方法返回当前类型,那么使用公共虚拟对象Clone()会容易得多。

那么让我们来看看“终极”解决方案——c#中有什么真正的意图让我们感到舒适?扩展方法!

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;
}

它被命名为Copy,以避免与当前的Clone方法冲突(编译器更喜欢类型自己声明的方法而不是扩展方法)。类约束是为了速度(不需要空检查等)。

我希望这能澄清为什么不让ICloneable<T>的原因。但是,建议完全不要实现ICloneable。