2017-02-08 25 views
0

私はクラスObservableCollectionと他のプロパティを持っています。 は、だから、少しのようになります。クローンObservableCollection

public class A 
{ 
    public int Id { get; set; } 
    ... 
    public object AValue {get; set;} 
} 

私は、このクラスのクローンオブジェクトをしたいと思います。 AValueプロパティはObservableCollectionまたは別のオブジェクトにすることができます。 AValueがObservableCollection型で、オブジェクトを追加しようとすると、クローンが元のオブジェクトと同じオブジェクトを持っているようです。クローンメソッドをAValueプロパティにのみ使用すると、クラスAのオブジェクトにはなりません。答えを

private object Clone(object obj) 
    { 
     var t = obj.GetType(); 

     if (obj == null) 
      return null; 

     if (t.IsValueType || t == typeof(string)) 
     { 
      return obj; 
     } 
     else if (t.IsGenericType) 
     { 
      if (obj is IList) 
      { 
       var c= typeof(ObservableCollection<>); 
       var cType = type.GetGenericArguments().First(); 
       var gType = c.MakeGenericType(cType); 
       var newC = (IList)Activator.CreateInstance(gType); 

       foreach (var item in (IEnumerable)obj) 
        newC.Add(item); 

       return newC; 
      } 
     } 
     else if (t.IsClass) 
     { 
      object objV = Activator.CreateInstance(type); 
      FieldInfo[] fields = t.GetFields(BindingFlags.Public | 
         BindingFlags.NonPublic | BindingFlags.Instance); 
      foreach (FieldInfo field in fields) 
      { 
       object fieldV = field.GetValue(obj); 
       if (fieldValue == null) 
        continue; 
       field.SetValue(objV, Clone(fieldV)); 
      } 
      return obj; 
     } 
     throw new ArgumentException("Unknown type"); 
    } 
} 

編集 感謝:私が使用しようとしたオブジェクトのクローンを作成するには。 あなたのコード@Sefeを追加しましたが、まだ動作しません。私は他のタイプがクローンしないことを知っていますが、まずリストを使ってやりたいと思います。私は間違いがどこにあるか分からない。 Aクラスのオブジェクトを取得し、オブジェクトをクローンし、クラスオブジェクトをダイアログボックスに送信します。私はクローンと元来のコレクションとプロパティを変更して同じです。 それはリストのジェネリック型

ObservableCollection<B> = new ObservableCollection<B>(); 

public class B: Base, ICloneable 
{ 
    ... 
    public object Clone() 
    { 
    return this.MemberwiseClone(); 
    } 

}

にIClonableインターフェイスを追加するenoughtだ、それは一般的なタイプは、別のクラスから継承することが重要ですか?

+0

コードにバグがあります。リストではないジェネリック型はどうですか?彼らはクローンされません。 – Sefe

+0

@Sefe私もそれを見つけましたが、その場合例外がスローされます(これはおそらくNotImplementedExceptionかもしれませんが)。 –

答えて

3

コレクションを複製していますが、アイテムを複製していません。コレクションの深いクローンを作成するには、アイテム(可能な場合)をクローンする必要があります。

foreach (var item in (IEnumerable)obj) { 
    ICloneable cloneable = item as ICloneable; 
    if (cloneable != null) { 
     newC.Add(cloneable.Clone()); 
    } 
    else { 
     newC.Add(item); 
    } 
} 

ICloneableインタフェースを使用すると、.NETフレームワークの組み込み方法です、あなたはにframweorkメソッドを期待することができます必要に応じてそれを認識してください。だからこれは好ましい方法でしょう。あなたの代わりに、独自の既存のClone方法を再利用したい場合は、再帰的に呼び出すことができます。

foreach (var item in (IEnumerable)obj) { 
    newC.Add(Clone(item)); 
} 

をUPDATE(質問の編集をアドレスするには):

あなたがMemberwiseCloneすべてフィールドを使用する場合と、イベントはクローンに転送されます。 MemberwiseCloneの浅いコピーを作成するので、フィールドと割り当てられたイベントハンドラが転送されます。したがって、他の参照タイプを含むフィールドがある場合、これらは(たとえそれらがICloneableであっても)クローンされません。また、orginalに割り当てられたイベントハンドラも、クローンに割り当てられます。

ICloneable.Cloneメソッドは、クローンを有効な状態にするために注意する必要があります。有効なものはケースごとに異なるため、.NETフレームワークに自動ディープ・クローニングはありません。 MemberwiseCloneを呼び出すのは良いスタートですが、浅いクローンを深いクローンに "アップグレード"するには、含まれているオブジェクト、イベントハンドラなどを検索しなければなりません。

+0

コレクションを頻繁にコピーする必要があるときに、コンテナの拡張機能を書きました。TContainer:ICollection 、new() 'が署名されています。 通常のジェネリックはすべて 'new()'を持っていますので、一般的に遭遇するリストなどのために機能します。関数はソースコンテナを繰り返し、 'Clone()'要素を反復してクローンコンテナに追加します。ディクショナリには、キーと値を複製する特殊な処理が必要であることに注意してください。 –