是否存在通用ICloneable
不存在的特殊原因?
如果我不想在每次克隆东西时都需要施放它,那会更舒服.
除了安德烈的答复(我同意,+1) -当ICloneable
是做了,你也可以选择明确的实施,使公众Clone()
返回一个类型的对象:
public Foo Clone() { /* your code */ } object ICloneable.Clone() {return Clone();}
当然,第二个问题是泛型ICloneable
继承.
如果我有:
public class Foo {} public class Bar : Foo {}
我实施了ICloneable
,然后实施了ICloneable
吗?ICloneable
?你很快就开始实现了很多相同的接口......与演员相比......真的很糟糕吗?
ICloneable现在被认为是一个糟糕的API,因为它没有指定结果是深拷贝还是浅拷贝.我认为这就是为什么他们不改进这个界面.
您可以执行类型化克隆扩展方法,但我认为它需要不同的名称,因为扩展方法的优先级低于原始方法.
我需要问一下,除了实现它之外,你究竟会对接口做些什么呢?接口通常仅在您转换为它时才有用(即此类支持'IBar'),或者具有接受它的参数或设置器(即我采用'IBar').使用ICloneable - 我们经历了整个框架,并且未能在任何地方找到一个不同于其实现的单一用法.我们也未能在"现实世界"中找到任何除了实现它之外的其他用法(在我们有权访问的~60,000个应用程序中).
现在,如果您只想强制执行一个您希望"可复制"对象实现的模式,那么这是一个非常好的用法 - 并继续.您还可以确定"克隆"对您意味着什么(即深或浅).但是,在这种情况下,我们(BCL)不需要定义它.当需要交换类型为不相关库之间的抽象的实例时,我们只在BCL中定义抽象.
大卫基恩(BCL队)
我认为"为什么"这个问题是不必要的.有很多接口/类/等...这非常有用,但不是.NET Frameworku基础库的一部分.
但是,主要是你可以自己做.
public interface ICloneable: ICloneable { new T Clone(); } public abstract class CloneableBase : ICloneable where T : CloneableBase { public abstract T Clone(); object ICloneable.Clone() { return this.Clone(); } } public abstract class CloneableExBase : CloneableBase where T : CloneableExBase { protected abstract T CreateClone(); protected abstract void FillClone( T clone ); public override T Clone() { T clone = this.CreateClone(); if ( object.ReferenceEquals( clone, null ) ) { throw new NullReferenceException( "Clone was not created." ); } return clone } } public abstract class PersonBase : CloneableExBase where T : PersonBase { public string Name { get; set; } protected override void FillClone( T clone ) { clone.Name = this.Name; } } public sealed class Person : PersonBase { protected override Person CreateClone() { return new Person(); } } public abstract class EmployeeBase : PersonBase where T : EmployeeBase { public string Department { get; set; } protected override void FillClone( T clone ) { base.FillClone( clone ); clone.Department = this.Department; } } public sealed class Employee : EmployeeBase { protected override Employee CreateClone() { return new Employee(); } }
这是很容易写自己的界面,如果你需要它:
public interface ICloneable: ICloneable where T : ICloneable { new T Clone(); }
最近阅读了文章为什么要复制一个对象是一件可怕的事情?,我认为这个问题需要额外的肯定.这里的其他答案提供了很好的建议,但答案仍然不完整 - 为什么不ICloneable
呢?
用法
所以,你有一个实现它的类.虽然以前你有一个想要的方法ICloneable
,但它现在必须是通用的才能接受ICloneable
.你需要编辑它.
然后,你可能有一个方法来检查一个对象is ICloneable
.现在怎么办?你不能这样做is ICloneable<>
,因为你不知道在compile-type中对象的类型,你不能使该方法通用.第一个真实问题.
所以,你需要同时拥有ICloneable
和ICloneable
,前者实现了后者.因此,实施者需要实现这两种方法 - object Clone()
和T Clone()
.不,谢谢,我们已经有了足够的乐趣IEnumerable
.
正如已经指出的那样,继承的复杂性也很大.虽然协方差似乎可以解决这个问题,但派生类型需要实现ICloneable
自己的类型,但是已经有一个方法具有相同的签名(基本上是=参数) - Clone()
基类的方法.使您的新克隆方法界面显式无意义,您将失去创建时所寻求的优势ICloneable
.所以添加new
关键字.但是不要忘记你还需要覆盖基类' Clone()
(对于所有派生类,实现必须保持一致,即从每个克隆方法返回相同的对象,因此必须使用基本克隆方法virtual
)!但是,遗憾的是,你不能同时使用相同的签名override
和new
方法.选择第一个关键字,您将失去添加时想要的目标ICloneable
.选择第二个,你将破坏界面本身,使得应该做同样的方法返回不同的对象.
点
你想要ICloneable
舒适,但舒适不是界面的设计,它们的意义是(通常是OOP)来统一对象的行为(尽管在C#中,它仅限于统一外部行为,例如方法和属性,而不是他们的工作).
如果第一个原因尚未说服您,那么您可以ICloneable
限制性地限制从克隆方法返回的类型.但是,讨厌的程序员可以实现ICloneable
T不是实现它的类型.因此,为了实现您的限制,您可以为泛型参数添加一个很好的约束:
public interface ICloneable
当然没有那个限制where
,您仍然不能限制T是实现接口的类型(您可以从ICloneable
不同类型派生实现它).
你看,即使这个目的也无法实现(原来ICloneable
也失败了,没有接口可以真正限制实现类的行为).
正如您所看到的,这证明了通用接口既难以完全实现,也非常不需要和无用.
但回到这个问题,你真正寻求的是在克隆物体时获得安慰.有两种方法可以做到:
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(); } }
该解决方案为用户提供了舒适性和预期的行为,但实施起来也太长了.如果我们不想让"舒适"方法返回当前类型,那么就更容易拥有public virtual object 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(this T obj) where T : class, ICloneable { return obj.Clone() as T; }
它被命名为Copy,不与当前的Clone方法冲突(编译器更喜欢类型自己声明的方法而不是扩展方法).该class
约束是有速度(不需要空检查等).
我希望这澄清了为什么不这样做的原因ICloneable
.但是,建议不要实施ICloneable
.