2012-06-17 11 views
6

私はC#で書かれたいくつかのコードに取り組んでいます。このアプリでは、次のように定義されたカスタムコレクションを持っています:C#オブジェクトのディープコピー

public class ResultList<T> : IEnumerable<T> 
{ 
    public List<T> Results { get; set; } 
    public decimal CenterLatitude { get; set; } 
    public decimal CenterLongitude { get; set; } 
} 

結果で使用されるタイプは、3つのカスタムタイプのいずれかです。各カスタムタイプのプロパティは単なるプリミティブ型(int、文字列、bool、int?、bool?)です。次のカスタムタイプの例を示します。

public class ResultItem 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public bool? isLegit { get; set; } 
} 

作成したResultListオブジェクトのディープコピーを実行するにはどうすればよいですか。私はこの投稿を見つけました:Generic method to create deep copy of all elements in a collection。しかし、私はそれを行う方法を把握することはできません。

+0

あなたは何を試してみましたか?どのようなエラーメッセージがありますか?あなたが見つけたJon Skeetのコードは、私が見る限りでは簡単に動作します。 –

+0

浅いか深いコピー? http://stackoverflow.com/questions/11073196/shallow-copy-of-a-custom-c-sharp-object –

+0

あなたと[this queston]のOPはなぜですか(http://stackoverflow.com/questions/ 11073196 /あなたの例ではまったく同じデータ構造を使用しているように思われる浅いカスタムCシャープオブジェクトのコピー)? –

答えて

8

ワンJon Skeetのexampleは、ICloneableインターフェイスを実装していないためです。

クローン化が必要なすべてのクラスでICloneableを実装します。

public class ResultList<T> : IEnumerable<T>, ICloneable where T : ICloneable 
{ 
    public List<T> Results { get; set; } 
    public decimal CenterLatitude { get; set; } 
    public decimal CenterLongitude { get; set; } 

    public object Clone() 
    { 
    var list = new ResultList<T> 
       { 
        CenterLatitude = CenterLatitude, 
        CenterLongitude = CenterLongitude, 
        Results = Results.Select(x => x.Clone()).Cast<T>().ToList() 
       }; 
    return list; 
    } 
} 

は、その後、あなたのオブジェクトのディープコピーを作成するには:

public class ResultItem : ICloneable 
{ 
    public object Clone() 
    { 
    var item = new ResultItem 
       { 
        ID = ID, 
        Name = Name, 
        isLegit = isLegit 
       }; 
    return item; 
    } 
} 

もResultList上

ここ

resultList.clone(); 
+0

大きな説明。手伝ってくれてどうもありがとう。 – user70192

12

最小の符号化の努力を伴うアプローチは、BinaryFormatterを介してシリアライズおよびデシリアライズするアプローチです。

あなたは(Kilhoffer’s answerから取られた)は、次の拡張メソッドを定義できます

public static T DeepClone<T>(T obj) 
{ 
    using (var ms = new MemoryStream()) 
    { 
     var formatter = new BinaryFormatter(); 
     formatter.Serialize(ms, obj); 
     ms.Position = 0; 
     return (T)formatter.Deserialize(ms); 
    } 
} 

を...そしてちょうど呼び出す:あなたのResultListクラスは動作しません理由の

ResultList<T> clone = DeepClone(original); 
1

はそれをコピーするためにリフレクションを使用して、私が必要と書いたものですすべてのプロパティ(指定されている場合はプライベートプロパティ)

public static class ObjectCloner 
{ 
    public static T Clone<T>(object obj, bool deep = false) where T : new() 
    { 
     if (!(obj is T)) 
     { 
      throw new Exception("Cloning object must match output type"); 
     } 

     return (T)Clone(obj, deep); 
    } 

    public static object Clone(object obj, bool deep) 
    { 
     if (obj == null) 
     { 
      return null; 
     } 

     Type objType = obj.GetType(); 

     if (objType.IsPrimitive || objType == typeof(string) || objType.GetConstructors().FirstOrDefault(x => x.GetParameters().Length == 0) == null) 
     { 
      return obj; 
     } 

     List<PropertyInfo> properties = objType.GetProperties().ToList(); 
     if (deep) 
     { 
      properties.AddRange(objType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic)); 
     } 

     object newObj = Activator.CreateInstance(objType); 

     foreach (var prop in properties) 
     { 
      if (prop.GetSetMethod() != null) 
      { 
       object propValue = prop.GetValue(obj, null); 
       object clone = Clone(propValue, deep); 
       prop.SetValue(newObj, clone, null); 
      } 
     } 

     return newObj; 
    } 
} 
+0

リストを継承するオブジェクトを処理する:コメント内のコードが吸い込まれてから2番目の答えを作成します。 – jeromeyers

3

はゲオルギ・それ@の拡大、私はそのタイプのリストを継承するプロパティを処理するために、自分のコードを変更する必要がありました:

public static class ObjectCloner { 
    public static T Clone<T>(object obj, bool deep = false) where T : new() { 
     if (!(obj is T)) { 
      throw new Exception("Cloning object must match output type"); 
     } 

     return (T)Clone(obj, deep); 
    } 

    public static object Clone(object obj, bool deep) { 
     if (obj == null) { 
      return null; 
     } 

     Type objType = obj.GetType(); 

     if (objType.IsPrimitive || objType == typeof(string) || objType.GetConstructors().FirstOrDefault(x => x.GetParameters().Length == 0) == null) { 
      return obj; 
     } 

     List<PropertyInfo> properties = objType.GetProperties().ToList(); 
     if (deep) { 
      properties.AddRange(objType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic)); 
     } 

     object newObj = Activator.CreateInstance(objType); 

     foreach (var prop in properties) { 
      if (prop.GetSetMethod() != null) { 
       var proceed = true; 
       if (obj is IList) { 
        var listType = obj.GetType().GetProperty("Item").PropertyType; 
        if (prop.PropertyType == listType) { 
         proceed = false; 
         foreach (var item in obj as IList) { 
          object clone = Clone(item, deep); 
          (newObj as IList).Add(clone);        
         }       
        }      
       } 

       if (proceed) { 
        object propValue = prop.GetValue(obj, null); 
        object clone = Clone(propValue, deep); 
        prop.SetValue(newObj, clone, null); 
       }     
      } 
     } 

     return newObj; 
    } 
} 
関連する問題