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

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


当前回答

除了Andrey的回复(我同意,+1)-当ICloneable完成时,你还可以选择显式实现,使公共Clone()返回一个类型化对象:

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

当然,泛型ICloneable<T> -继承还有第二个问题。

如果我有:

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

我实现了ICloneable<T>,那么我实现了ICloneable<Foo>吗?酒吧ICloneable < > ?你很快就开始实现许多相同的接口…… 与演员相比……真的有那么糟糕吗?

其他回答

这是一个非常好的问题……不过,你也可以自己制作:

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

安德烈说它被认为是一个糟糕的API,但我还没有听到任何关于这个接口被弃用的消息。这将破坏大量的接口…… Clone方法应该执行浅拷贝。 如果对象还提供深度复制,则可以使用重载Clone (bool deep)。

编辑:模式我用于“克隆”一个对象,是在构造函数中传递一个原型。

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

这消除了任何潜在的冗余代码实现情况。 顺便说一下,谈到ICloneable的局限性,是否应该执行浅克隆或深克隆,甚至是部分浅克隆/部分深克隆,难道不是由对象本身决定的吗?只要对象按预期工作,我们真的应该关心吗?在某些情况下,一个好的Clone实现很可能同时包括浅克隆和深克隆。

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

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

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

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

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

我认为“为什么”这个问题是不必要的。有很多接口/类等…它非常有用,但不是. 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();
}