2012-10-19 8 views
6

はのは、私は以下のクラス階層(ベース・インタフェース付属)を持っているとしましょう:C#クラス階層のディープコピー/クローンメソッド - どこでも具体的な実装が必要ですか?

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()には関連するものがあります。そのため、メソッドまたはコピーコンストラクタは実装されません。新しいImmediateActionをインスタンス化しているので、ImmediateAction.DeepClone()が代わりに呼び出され、MovementActionDeepClone()を実装していない - 私はここで何が起こっているかを理解し、今

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

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

:私がいる

問題は、このです。したがって、上記の例のyのタイプはMovementActionの代わりにImmediateActionです。

この長いプリアンブルの後、私の質問はこれです:このような状況のためのベストプラクティスは何ですか?私は立ち往生ですか? にはがあり、DeepClone()メソッドを実装するには、階層に沿ったすべてのクラスについて何かが必要ですか?私がここで使用しているパターンは間違っていますか?が良い方法です

最終的な注記:できる限り、私は反射を避けたいと思います。

+0

なぜあなたは反射を避けたいですか? –

+0

これはゲームで使用されており、ゲームプレイやロード中だけでなく潜在的に使用される可能性があるので、反射のオーバーヘッドを避けたいと思います。ちょっとした背景:通常、JSON/XML定義を使って項目を読み込みますが、IActionファクトリ(および他のファクトリ)はタイプ別にIAをキャッシュし、格納された参照を複製してXMLに戻って再度読み込まないようにします。(プールは別の選択肢でしたが、潜在的な種類のアクションがあり、プロパティやプロパティが異なるため、数百もの異なるプールがなくても実行可能なプールソリューションを見ることはできません) – Terminal8

+0

私には問題があるようです。 'IAction'として扱うことを計画していて、' DeepClone'と呼ばれるオブジェクトの元の型を保存することが重要な場合は、IActionを実装するすべての具体的なクラスにDeepCloneを記述しますそれが正しい種類のオブジェクトを確実に作成できるようになります。幸いにも、それらを書くことは自明です。 – itsmatt

答えて

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(); 
    } 
} 
+0

私はこの解決策が好きです! クラスごとに( 'CopyInto'を実装する)ものは、百万の' DeepClone() 'に広がるのではなく、オブジェクトのインスタンス化を単一の場所に置きます。簡単に追加することもできます!ありがとう! – Terminal8

0

通常、具体的なクラスにクローンメソッドを実装する必要があります。

return new ImmediateAction(this); 
+0

ああ、それは私の間違いでした即時抽象ではありません – Terminal8

2

はそうです、あなたは、2つのオプションがあります。:実際にはあなたが投稿このコードは、あなたが一番上に述べたようにImmediateActionが抽象的である場合にはコンパイルされませんどちらか

  • をDeepCloneに()するたびに実装し、詳細(リストすべて共有されない性質)
  • または反射
関連する問題