我正在重新提出一个我刚问过的问题,但我想以更简洁的方式重新提出这个问题,因为我认为这引起了一些混乱。
我有一个基类:RoomObject。 我有两个子类:Bed和Table,它继承自RoomObject。
我有一个变量currentObject,它是RoomObject类型,但实际上会包含一个Bed或Table的实例(RoomObject永远不会自己实例化)。
如何在不知道其完整类型的情况下克隆我的currentObject?
即。如果currentObject是一张床,我想用
克隆床currentObject = new Bed(currentObject);
如果currentObject是一个表,我想使用
currentObject = new Table(currentObject);
我可以通过调用Activator.CreateInstance(currentObject.GetType())来使用反射,然后复制我需要的任何属性,但这看起来很麻烦。
答案 0 :(得分:6)
您应该使用称为虚拟构造函数的模式或克隆方法。
向RoomObject
添加一个虚拟方法,返回当前对象的副本:
abstract RoomObject Clone();
现在在Bed
中实现此方法以返回new Bed(...)
,并在Table
中返回new Table(...)
。传递Bed
和Table
的构造函数所需的任何参数,以复制当前对象中的内容。
.NET有一个接口ICloneable
,通常用于实现此模式。这种方法的一个小缺点是Clone
必须返回object
,而不是RoomObject
,所以如果您需要RoomObject
,则需要投出它。
答案 1 :(得分:1)
这是关于反射的最好的事情之一:能够在没有客户端代码知道它的类型的情况下创建对象。有时它可能会变得混乱,甚至有时会使代码变慢,但是 - 如果使用得当 - 将使您的代码更易于管理。
例如,请查看the Factory Pattern,以及如何实施with Reflection和here as well
答案 2 :(得分:1)
我认为一个解决方案是为所有对象实现ICloneable接口。这是一些示例代码:
class RoomObject : ICloneable
{
public abstract object Clone();
}
class Bed : ICloneable
{
public override object Clone()
{
return new Bed();
}
}
class Table : ICloneable
{
public override object Clone()
{
return new Table();
}
}
class Program
{
public static void Main(String[] args)
{
RoomObject ro = /* from some other places*/
RoomObject newOne = ro.Clone() as RoomObject; /* here's what you what */
}
}
答案 3 :(得分:1)
而不是那样,实现.NET Framework上开箱即用的ICloneable
接口,正如其他人在答案中所说的那样。
由于ICloneable.Clone()
方法返回object
,那么同时实现ICloneable<T>
的自定义ICloneable
呢?
public interface ICloneable<T> : ICloneable
where T : class
{
T TypedClone();
}
public class MyCloneableObject : ICloneable<MyCloneableObject>
{
public string Some { get; set; }
public object Clone()
{
MyCloneableObject clone = new MyCloneableObject { Some = this.Some };
}
public MyCloneableObject TypedClone()
{
return (MyCloneableObject)Clone();
}
}
稍后,在您的代码中......
MyCloneableObject some = new MyCloneableObject();
if(some is ICloneable<MyCloneableObject>)
{
MyCloneableObject myClone = some.TypedClone();
// .. or the standard `Clone()`:
myClone = (MyCloneableObject)some.Clone();
}
实现内置和自定义界面是一个好主意,因为您的克隆可以与其他可能接受ICloneable
实现的库一起运行。
最后,不应使用反射,这种情况应该在设计时解决。我认为如果你不能修改包含ICloneable
想要的人的库,就应该做反射。