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ここで、関連するものがまったく内部にDeepClone()ないため、メソッドまたはコピーコンストラクターを実装していないとしましょう。

私が抱えている問題はこれです:

IAction x = new MovementAction();
IAction y = x.DeepClone();

//pleaseBeTrue is false
bool pleaseBeTrue = y is MovementAction;

今、私はここで何が起こっているのか理解しています -MovementActionは実装されていないためDeepClone()ImmediateAction.DeepClone()代わりに呼び出され、 new をインスタンス化しますImmediateAction。したがって、y上記の例の の型はImmediateActionではなく ですMovementAction

この長い序文の後で、私の質問は次のとおりです。この種の状況でのベスト プラクティスは何ですか? 私は立ち往生していますか?階層に沿ったすべてのクラスに対して、があってもメソッド を実装する必要がありますか? ここで使用しているパターンは間違っていますか?もっと良い方法がありますか?DeepClone()

最後に 1 つ: 可能であれば内省を避けたいと思います。

4

3 に答える 3

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 に答える
2

はい、次の 2 つのオプションがあります。

  • 毎回 DeepClone() を詳細に実装します (共有されていないすべてのプロパティをリストします)。
  • または、「quick&dirty」を使用しますが、リフレクションを使用して実装を共有します
于 2012-10-19T01:35:34.603 に答える
0

通常、具象クラスに clone メソッドを実装する必要があります。実際、上で述べたように ImmediateAction が抽象的である場合、投稿したこのコードはコンパイルされません。

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