假设我有以下类层次结构(包括基本接口):
IAction -> (abstract) BaseAction -> (concrete) ImmediateAction -> (concrete) MovementAction
现在,让我们说IAction公开了一个方法(嗯,实际上是IAction实现的不同接口,但让我们在这里保持简单!):
// Returns a new IAction instance deep copied from the current instance.
IAction DeepClone();
到目前为止好吗?我们有深度复制方法,ImmediateAction
有一些它想要复制的属性,因此它不仅提供DeepClone()
的实现,还提供复制构造函数:
//Base Action implementation
protected BaseAction(BaseAction old)
{
this.something = old.something;
}
//Immediate Action Implementation
protected ImmediateAction(ImmediateAction old)
: base(old)
{
this.anything = old.anything;
}
public IAction DeepClone()
{
return new ImmediateAction(this);
}
现在,假设MovementAction
内部没有任何与DeepClone()
相关的内容,因此它不会实现方法或复制构造函数。
我遇到的问题是:
IAction x = new MovementAction();
IAction y = x.DeepClone();
//pleaseBeTrue is false
bool pleaseBeTrue = y is MovementAction;
现在,我了解这里发生了什么 - MovementAction
没有实现DeepClone()
,因此调用了ImmediateAction.DeepClone()
,实例化了一个新的ImmediateAction
。因此,上例中y
的类型为ImmediateAction
而非MovementAction
。
所以,在这个冗长的序言之后,我的问题是:这种情况的最佳做法是什么?我被困了?我是否只是 为层次结构中的每个类实现DeepClone()
方法,无论是什么?我在这里使用的模式是不正确的,还有更好的方式?
最后一点说明:如果可能,我想避免反思。
答案 0 :(得分:2)
所以是的,你有两个选择:
答案 1 :(得分:2)
可以使用扩展方法并进行增量克隆
public static class DeepCopyExt
{
public static T DeepCopy<T>(this T item)
where T : ThingBase, new()
{
var newThing = new T();
item.CopyInto(newThing);
return newThing;
}
}
public abstract class ThingBase
{
public int A { get; set; }
public virtual void CopyInto(ThingBase target)
{
target.A = A;
}
}
public class ThingA : ThingBase
{
}
public class ThingB : ThingA
{
public int B { get; set; }
public override void CopyInto(ThingBase target)
{
var thingB = target as ThingB;
if(thingB == null)
{
throw new ArgumentException("target is not a ThingB");
}
thingB.B = B;
base.CopyInto(thingB);
}
}
class Program
{
static void Main(string[] args)
{
var b = new ThingB
{
A = 1,
B = 3
};
//c is ThingB
var c = b.DeepCopy();
var b1 = new ThingA
{
A = 1,
};
//c1 is ThingA
var c1 = b1.DeepCopy();
Debugger.Break();
}
}
答案 2 :(得分:0)
通常,您需要在具体类中实现clone方法。事实上,如果您发布的立即行为是抽象的,那么您发布的此代码将无法编译:
return new ImmediateAction(this);