为什么可以';t我正确地键入了Clone()
本文关键字:Clone 正确地 为什么 | 更新日期: 2023-09-27 18:27:23
和其他C#程序员一样,我面临着如何最好地表达对象复制的问题。具体来说,我有一个类层次结构,其中所有对象都必须是可复制的。已经讨论过是使用复制构造函数(C#没有提供)还是使用Clone()
方法;另一种选择是使用一种方法来获取对象并生成副本。所有选项都有优缺点,但它们共同的一个问题是键入的问题。
我想以任何可能的方式声明,在我的类层次结构中的所有对象上都存在一个复制操作,它总是生成一个与原始类型相同的对象,这样任何违反此操作的行为都会在编译时报告。
这三个选项都不允许我这样做,即使使用泛型也是如此。显然,C#根本不允许我这么做;Java和我所知道的其他一些语言也是如此。
为什么不呢?类型系统中的这样一个功能是否太难实现?它是否会导致不一致?我想要一个准确打字的复印操作被认为是一个角落的情况吗?有没有其他我错过的实现这一目标的方法?
附言:请注意,这个问题根本不是关于浅复制和深复制的区别,如何复制,或者是否复制。
这里的部分问题是多态性。创建一个通用的ICloneable<T>
是微不足道的,但当你有时就会遇到问题
Foo : ICloneable<Foo>
Bar : Foo
因为现在CCD_ 3需要实现CCD_ 4和CCD_。幸运的是,您可以同时使用方法隐藏和多态性来使几乎工作,即
interface ICloneable<T> {
T Clone();
}
class Foo : ICloneable<Foo> {
protected virtual object Clone() { /*...*/ }
public Foo Clone() { return (Foo) Clone(); }
}
class Bar : Foo, ICloneable<Bar> {
protected override object Clone() { /*...*/ }
public new Bar Clone() { return (Bar) Clone(); }
}
然而!正如你所看到的,这种情况很快就会变得难以维持。也许更好的选择是使用内置的非通用ICloneable
和一种扩展方法:
public static T TypedClone<T>(this T source) where T : class, ICloneable
{
if(source == null) return null;
return (T)source.Clone();
}
然后你就可以有Foo : ICloneable
,只需使用:
Foo foo = ...
Foo clone = foo.TypedClone();
使用您的Foo
/Bar
class Foo : ICloneable {
public virtual object Clone() { /*...*/ }
}
class Bar : Foo {
public override object Clone() { /*...*/ }
}
单词的含义总是模糊不清。
您是指深度复制还是浅层复制 以Java这样的语言为例,它只有基元类型和引用,并以这样的类为例 现在,当您讨论复制上述类的对象时,您可能想要深度复制 以以下情况为例: 如果复制此对象,是否仍需要深度复制?字符串在java中是不可变的类型,因此在这种情况下,一个浅拷贝就足够了,并且拷贝的PairOfStrings对象只引用与源对象相同的字符串。 情况可能会变得更糟。在某些情况下,使用深层副本而不是浅层副本会造成损害。 在上面的例子中,parentCar显然是对轮子的父Car对象的引用,因此所有4个轮子都应该指向同一个父对象。 你现在想复制一个轮子,最好做一个浅复制,你会复制整个汽车。 正如您所看到的,使用面向对象编程来实现对象的复制过程并不那么明显。 这就是为什么Java使用Clone()方法来定义copy的含义,因为它不能自动知道,这是一个设计问题。 不过,如果您只想要一个对象的深度副本,您可以始终使用序列化。它就像一个符咒。class PairOfArrays {
int[] i1;
int[] i2;
}
class PairOfStrings {
String s1;
String s1;
}
class Wheel {
Car parentCar;
}
如果你想在类层次结构中实现一些克隆逻辑,为什么不这样声明你自己的接口:
interface IMyCloneable<T>
{
T Clone();
}
在支持克隆的每种类型中实现它。
我再次思考了这个问题,并个人得出结论,由于以下原因,这样的功能没有什么意义:
假设您有一个自己定义的对象层次结构:
- MyObject1
- MyObject2
- MyObject3
您的要求是:
- MyObject1必须具有MyObject1 clone()方法
- MyObject2必须具有MyObject2 clone()方法
- MyObject3必须具有MyObject3 clone()方法
现在,假设您直接使用任何一种方法,如
MyObject2 copy = someMyObject2.clone();
然后,编译器直接对您的方法调用进行类型检查,使您的需求变得无用。
假设你不直接使用它,那么有这个需求是没有用的,因为你有一个无论如何都不会使用的方法。
最后,假设您想使用一个通用接口,该接口允许您在不知道其类型的情况下复制层次结构中的对象:
List<Copyable> list = ...
for( Copyable obj : list ){
Copyable copy = obj.clone();
}
interface Copyable {
public Copyable copy();
}
在这种情况下,声明"每个对象都必须声明一个复制方法,返回类型与对象的类相同"也是没有用的,因为无论如何都不会直接使用对象类。
所以,你的问题是,你为什么想要这样一处房产?我认为这是导致OOP语言不支持这样一个特性的思路(我可能错了)。