为什么没有 ICloneable?
通用 ICloneable
不存在是否有特殊原因?
如果我不需要每次克隆某些东西时都投射它,那就会舒服得多。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
除了 Andrey 的回复(我同意,+1) - 当
ICloneable
完成时,您还可以选择显式实现来使公共Clone()
返回类型化对象:当然,通用
ICloneable
还存在第二个问题 - 继承。如果我:
并且我实现了
ICloneable
,那么我是否实现ICloneable
?ICloneable
? 您很快就开始实现许多相同的接口......与演员相比……真的有那么糟糕吗?
In addition to Andrey's reply (which I agree with, +1) - when
ICloneable
is done, you can also choose explicit implementation to make the publicClone()
return a typed object:Of course there is a second issue with a generic
ICloneable<T>
- inheritance.If I have:
And I implemented
ICloneable<T>
, then do I implementICloneable<Foo>
?ICloneable<Bar>
? You quickly start implementing a lot of identical interfaces...Compare to a cast... and is it really so bad?
ICloneable 现在被认为是一个糟糕的 API,因为它没有指定结果是深拷贝还是浅拷贝。 我认为这就是他们不改进这个界面的原因。
您可能可以执行类型化克隆扩展方法,但我认为它需要不同的名称,因为扩展方法的优先级低于原始方法。
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.
我想问,除了实现接口之外,您究竟会用该接口做什么? 接口通常仅在您强制转换时才有用(即此类是否支持“IBar”),或者具有接受它的参数或设置器(即我接受“IBar”)。 使用 ICloneable - 我们浏览了整个框架,但没有找到除了它的实现之外的任何单一用法。 我们也未能在“现实世界”中找到除了实现它之外的任何用途(在我们可以访问的约 60,000 个应用程序中)。
现在,如果您只想强制执行您希望“可克隆”对象实现的模式,那么这是一个完全好的用法 - 然后继续。 您还可以决定“克隆”对您到底意味着什么(即深克隆或浅克隆)。 然而,在这种情况下,我们(BCL)就没有必要定义它。 仅当需要在不相关的库之间交换类型为抽象的实例时,我们才在 BCL 中定义抽象。
大卫·基恩(BCL 队)
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)
我认为“为什么”这个问题是没有必要的。 有很多接口/类/等等...非常有用,但不是 .NET Frameworku 基础库的一部分。
但是,主要是你可以自己做。
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.
自己编写界面非常容易< /a> 如果你需要它:
It's pretty easy to write the interface yourself if you need it:
最近阅读了文章 为什么复制对象是一件可怕的事情?,我认为这个问题需要进一步澄清。 这里的其他答案提供了很好的建议,但答案仍然不完整 - 为什么没有
ICloneable
?使用
所以,你有一个实现它的类。 虽然以前您有一个需要
ICloneable
的方法,但现在它必须是通用的才能接受ICloneable
。 您需要对其进行编辑。然后,您可能有一个方法来检查对象是否
是 ICloneable
。 现在怎么办? 您不能执行 is ICloneable<> 并且由于您不知道编译类型时对象的类型,因此无法使该方法通用。 第一个真正的问题。因此您需要同时拥有
ICloneable
和ICloneable
,前者实现后者。 因此,实现者需要实现这两种方法 -object Clone()
和T Clone()
。 不,谢谢,我们已经从IEnumerable
中获得了足够的乐趣。正如已经指出的,继承也很复杂。 虽然协变似乎可以解决这个问题,但派生类型需要实现其自己类型的
ICloneable
,但已经有一个具有相同签名(= 参数,基本上)的方法 - <基类的 code>Clone() 。 使新的克隆方法接口显式化是没有意义的,您将失去创建ICloneable
时所寻求的优势。 因此添加new
关键字。 但不要忘记,您还需要重写基类的Clone()
(所有派生类的实现必须保持统一,即从每个克隆方法返回相同的对象,因此基本克隆方法必须是虚拟的)! 但不幸的是,您不能同时使用相同的签名来override
和new
方法。 选择第一个关键字,您将失去添加ICloneable
时想要达到的目标。 选择第二个,您将破坏接口本身,使应该执行相同操作的方法返回不同的对象。点
你想要
ICloneable
来获得舒适感,但舒适感并不是接口设计的目的,它们的含义是(在一般 OOP 中)统一对象的行为(尽管在 C# 中,它是仅限于统一外部行为,例如方法和属性,而不是它们的工作原理)。如果第一个原因还没有说服您,您可以反对
ICloneable
也可以限制性地工作,以限制从克隆方法返回的类型。 然而,讨厌的程序员可以实现ICloneable
,其中 T 不是实现它的类型。 因此,为了实现您的限制,您可以向通用参数添加一个很好的约束:公共接口 ICloneable; : ICloneable 其中 T : ICloneable
当然比没有
where
的限制更严格,您仍然不能限制 T 是实现接口的类型(您可以从ICloneable派生;
实现它的不同类型)。你看,连这个目的都无法实现(原来的
ICloneable
也失败了,没有接口能够真正限制实现类的行为)。正如您所看到的,这证明通用接口既难以完全实现,又确实不需要且无用。
但回到问题上来,你真正寻求的是克隆对象时的舒适感。 有两种方法可以做到这一点:
其他方法
该解决方案为用户提供了舒适度和预期行为,但实施起来也太长了。 如果我们不想让“舒适”的方法返回当前类型,那么使用
公共虚拟对象 Clone()
会容易得多。那么让我们看看“最终”解决方案 - C# 中的什么真正目的是为了给我们带来安慰?
扩展方法!
它被命名为Copy,以免与当前的Clone方法发生冲突(编译器更喜欢类型自己声明的方法而不是扩展方法)。
class
约束是为了速度(不需要空检查等)。我希望这能澄清为什么不使
ICloneable
的原因。 但是,建议根本不要实现ICloneable
。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>
?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 acceptICloneable<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 dois 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>
andICloneable
, the former implementing the latter. Thus an implementer would need to implement both methods -object Clone()
andT Clone()
. No, thanks, we already have enough fun withIEnumerable
.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) - theClone()
of the base class. Making your new clone method interface explicit is pointless, you will lose the advantage you sought when creatingICloneable<T>
. So add thenew
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 bevirtual
)! But, unfortunately, you can't bothoverride
andnew
methods with the same signature. Choosing the first keyword, you'd lose the goal you wanted to have when addingICloneable<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 implementICloneable<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 fromICloneable<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
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!
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 implementICloneable
at all.一个大问题是他们不能限制T是同一类。 例如,什么会阻止您这样做:
它们需要一个参数限制,例如:
A big problem is that they could not restrict T to be the same class. Fore example what would prevent you from doing this:
They need a parameter restriction like:
这是一个非常好的问题...不过,您可以自己提出:
Andrey 说它被认为是一个糟糕的 API,但我还没有听说过有关此接口被弃用的任何消息。 这会破坏大量的接口......
Clone 方法应该执行浅复制。
如果对象还提供深复制,则可以使用重载的 Clone ( bool deep )。
编辑:我用于“克隆”对象的模式是在构造函数中传递原型。
这消除了任何潜在的冗余代码实现情况。
顺便说一句,谈论 ICloneable 的局限性,难道不是由对象本身来决定是否应该执行浅克隆或深克隆,甚至是部分浅/部分深克隆吗? 只要该对象按预期工作,我们真的应该关心吗? 在某些情况下,一个好的克隆实现很可能包括浅克隆和深克隆。
It's a very good question... You could make your own, though:
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.
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.