如何克隆继承的对象?
我有一个具有此方法的 Tile
类:
public object Clone()
{
return MemberwiseClone();
}
以及另一个继承自 Tile
的类 Checker
。
我还有一个 Board
类,它是一个 List
。我想克隆板,所以我写了这个:
public Board Clone()
{
var b = new Board(width, height);
foreach (var t in this) b.Add(t.Clone());
return b;
}
但它抛出了一个错误:
无法从“object”转换为“Checkers.Tile”
现在我可以使 Tile.Clone
方法返回一个 Tile
,但随后 MemberwiseClone
code> 也复制子Checker
中的附加属性吗?
如果这不是问题,那么上面的 Board.Clone 方法和这个方法之间的语义差异是什么?
public Board Clone()
{
using (var ms = new MemoryStream())
{
var bf = new BinaryFormatter();
bf.Serialize(ms, this);
ms.Position = 0;
return (Board)bf.Deserialize(ms);
}
}
因为它们肯定会对我的程序产生不同的影响,即使当我打印电路板时它看起来是一样的。我不认为有什么东西被克隆,但正在返回一个引用。 Board
构造函数如下所示:
public Board(int width = 8, int height = 8)
{
this.width = width;
this.height = height;
this.rowWidth = width / 2;
this.Capacity = rowWidth * height;
}
Tile
类实际上没有任何属性。检查器只有两个枚举属性:
public enum Color { Black, White };
public enum Class { Man, King };
public class Checker : Tile
{
public Color Color { get; set; }
public Class Class { get; set; }
I've got a Tile
class with this method:
public object Clone()
{
return MemberwiseClone();
}
And another class Checker
that inherits from Tile
.
I also have a Board
class that is a List<Tile>
. I want to clone the board, so I wrote this:
public Board Clone()
{
var b = new Board(width, height);
foreach (var t in this) b.Add(t.Clone());
return b;
}
But it throws an error:
cannot convert from 'object' to 'Checkers.Tile'
Now I can make the Tile.Clone
method return a Tile
instead, but then will the MemberwiseClone
copy the additional properties in the sub-Checker
as well?
If that's not the problem, what's the semantic difference between the above Board.Clone
method and this?
public Board Clone()
{
using (var ms = new MemoryStream())
{
var bf = new BinaryFormatter();
bf.Serialize(ms, this);
ms.Position = 0;
return (Board)bf.Deserialize(ms);
}
}
Because they're definitely having different effects on my program, even though when I print the board it looks the same. I don't think something is being cloned but a reference is being returned. The Board
ctor looks like this:
public Board(int width = 8, int height = 8)
{
this.width = width;
this.height = height;
this.rowWidth = width / 2;
this.Capacity = rowWidth * height;
}
The Tile
class actually doesn't have any properties. The checker just has two enums properties:
public enum Color { Black, White };
public enum Class { Man, King };
public class Checker : Tile
{
public Color Color { get; set; }
public Class Class { get; set; }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的,MemberwiseClone 也会复制
仅检查器字段。 MemberwiseClone 无法知道您的
Clone
方法的返回类型;因此,它的行为不能依赖于它。关于克隆实现和序列化之间的差异:
MemberwiseClone
创建 Tiles 的浅拷贝:如果 Tile(或 Checker)引用某个对象,则 Tile 的克隆仍然引用相同对象(而不是它的副本)。另一方面,您的序列化代码是创建主板深层副本的众所周知的做法 :整个依赖对象树被序列化和反序列化。
当然,只有当您的图块(或跳棋)包含具有引用类型的字段时,这才会产生影响。
Yes, MemberwiseClone will also copy the
Checker
-only fields. MemberwiseClone cannot know the return type of yourClone
method; therefore, it's behaviour cannot depend on it.About the difference betweeen your Clone implementation and the serialization:
MemberwiseClone
creates a shallow copy of the Tiles: If a Tile (or Checker) references some object, the Tile's clone still references the same object (rather than a copy of it).On the other hand, your serialization code is a well known practice for creating a deep copy of your board: The whole tree of dependent objects is serialized and deserialized.
Of course, this only makes a difference if your Tiles (or Checkers) contain fields with reference types.
在我看来,关于克隆,有四种主要的对象类别:
Unfortunately, there's generally no nice way to distinguish #1 and #2 unless a type obscures the MemberwiseClone method. I like to refer to type #3 as semi-cloneable.
半克隆对象应该支持受保护的虚拟方法,称为 CloneBase 之类的方法,该方法将返回 Object 或基类类型(在实践中这并不重要);最低级别的 CloneBase 方法应该调用 MemberwiseClone 并执行任何必要的操作来修复克隆的对象。任何支持克隆的派生类都应该有一个公共 Clone 方法,该方法只需调用 CloneBase 并对结果进行类型转换。在基类级别克隆之后修复和对象所需的任何派生类逻辑都应该覆盖 CloneBase。
如果可能需要不支持克隆的派生类,则公开一个半可克隆类,并从该类继承一个 CloneableWhatever,它除了添加公共 Clone 方法之外什么也不做。这样,不可克隆的类可以从半可克隆的类派生,而可克隆的类可以从 CloneableWhatever 派生。
As I see it, there are four main classes of object, with respect to cloning:
Unfortunately, there's generally no nice way to distinguish #1 and #2 unless a type obscures the MemberwiseClone method. I like to refer to type #3 as semi-cloneable.
A semi-cloneable object should support a protected virtual method called something like CloneBase which will return either Object or the base class type (it won't matter much in practice); the lowest-level CloneBase method should call MemberwiseClone and do whatever is necessary to fix up the cloned object. Any derived class which supports cloning should have a public Clone method which simply calls CloneBase and typecasts the result. Any derived-class logic necessary to fix up and object after base-class-level cloning should go in an override of CloneBase.
If there may be any need for a derived class which does not support cloning, then make public a semi-cloneable class and inherit from that class a CloneableWhatever which does nothing except add the public Clone method. In that way, non-cloneable classes can derive from the semi-cloneable class, and cloneable ones can derive from CloneableWhatever.
是的,它会的 - 它是多态性。
Yes, it will - it's polymorphism.