6

假设我有以下类层次结构(包括基本接口):

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它里面没有任何与 a 相关的东西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()方法 ?我在这里使用的模式是否不正确,还有更好的方法吗?

最后一点:如果可能的话,我想避免反思。

4

3 回答 3

2

所以是的,你有两个选择:

  • 每次都执行 DeepClone() 并详细说明(列出所有未共享的属性)
  • 或使用“quick&dirty”但使用反射共享实现
于 2012-10-19T01:35:34.603 回答
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();
    }
}
于 2012-10-19T05:09:16.640 回答
0

通常,您需要在具体类中实现您的克隆方法。实际上,如果 ImmediateAction 像您在顶部所说的那样抽象,则您发布的这段代码将无法编译:

return new ImmediateAction(this);
于 2012-10-19T00:51:22.500 回答