public static T DeepCopy<T>(T obj) { if (obj == null) throw new ArgumentNullException("Object cannot be null"); return (T)Process(obj); } static object Process(object obj) { if (obj == null) return null; Type type = obj.GetType(); if (type.IsValueType || type == typeof(string)) { return obj; } else if (type.IsArray) { Type elementType = Type.GetType( type.FullName.Replace("[]", string.Empty)); var array = obj as Array; Array copied = Array.CreateInstance(elementType, array.Length); for (int i = 0; i < array.Length; i++) { copied.SetValue(Process(array.GetValue(i)), i); } return Convert.ChangeType(copied, obj.GetType()); } else if (type.IsClass) { object toret = Activator.CreateInstance(obj.GetType()); //FieldInfo[] fields = type.GetFields(BindingFlags.Public | // BindingFlags.NonPublic | BindingFlags.Instance); FieldInfo[] fields = GetAllFields(type).ToArray(); foreach (FieldInfo field in fields) { object fieldValue = field.GetValue(obj); if (fieldValue == null) continue; field.SetValue(toret, Process(fieldValue)); } return toret; } else { return null; //throw new ArgumentException("Unknown type"); } } public static IEnumerable<FieldInfo> GetAllFields(Type t) { if (t == null) return Enumerable.Empty<FieldInfo>(); BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly; return t.GetFields(flags).Union(GetAllFields(t.BaseType)); } Note that If we restrict to Serializable then using Memory Stream can deep copy class Program { static void Main(string[] args) { Outside o = new Outside() { Data = new Inside() { Name = "n1", Price = 199 } }; Outside o_sc = o.ShadowCopy; o_sc.Data.Name = "Changed"; // change o as well since Shadow copy reference Outside o_dc = o.DeepCopy; o_dc.Data.Name = "Reset"; // not affect o } } [Serializable] public class Outside { public Inside Data { get; set; } public Outside ShadowCopy { get { return MemberwiseClone() as Outside ; } } public Outside DeepCopy { get { MemoryStream m = new MemoryStream(); BinaryFormatter b = new BinaryFormatter(); b.Serialize(m, this); m.Position = 0; return b.Deserialize(m) as Outside; } } } [Serializable] public class Inside { public string Name { get; set; } public double Price { get; set; } }
Wednesday, February 29, 2012
Deep Copy Helper
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment