diff --git a/DeepCloner/Helpers/DeepClonerExprGenerator.cs b/DeepCloner/Helpers/DeepClonerExprGenerator.cs index 78a3dd1..7f04ebb 100644 --- a/DeepCloner/Helpers/DeepClonerExprGenerator.cs +++ b/DeepCloner/Helpers/DeepClonerExprGenerator.cs @@ -141,8 +141,10 @@ private static object GenerateProcessMethod(Type type, bool unboxStruct) if (tp.Name == "ContextBoundObject") break; #endif - fi.AddRange(tp.GetDeclaredFields()); - tp = tp.BaseType(); + // Avoid to copy property change event handlers (or should we avoid to copy event handlers at all?) + var fields = tp.GetDeclaredFields().Where(x => !x.IsPropertyChangeEventHandler()); + fi.AddRange(fields); + tp = tp.BaseType(); } while (tp != null); diff --git a/DeepCloner/Helpers/DeepClonerGenerator.cs b/DeepCloner/Helpers/DeepClonerGenerator.cs index ed11965..fde6657 100644 --- a/DeepCloner/Helpers/DeepClonerGenerator.cs +++ b/DeepCloner/Helpers/DeepClonerGenerator.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.Linq; namespace Force.DeepCloner.Helpers @@ -33,8 +34,10 @@ private static object CloneClassRoot(object obj) if (cloner == null) return obj; - return cloner(obj, new DeepCloneState()); - } + var result = cloner(obj, new DeepCloneState()); + result = RemovePropertyChangeEventHandler(result); + return result; + } internal static object CloneClassInternal(object obj, DeepCloneState state) { @@ -52,10 +55,29 @@ internal static object CloneClassInternal(object obj, DeepCloneState state) if (knownRef != null) return knownRef; - return cloner(obj, state); - } - - private static T CloneStructInternal(T obj, DeepCloneState state) // where T : struct + var result = cloner(obj, state); + result = RemovePropertyChangeEventHandler(result); + return result; + } + + /// + /// Clears fields that store or instances. + /// + private static object RemovePropertyChangeEventHandler(object o) + { + var t = o.GetType(); + var fields = o.GetType().GetAllFieldsIncludingBaseTypes(); + foreach (var fieldInfo in fields) + { + if (fieldInfo.IsPropertyChangeEventHandler()) + { + fieldInfo.SetValue(o, null); + } + } + return o; + } + + private static T CloneStructInternal(T obj, DeepCloneState state) // where T : struct { // no loops, no nulls, no inheritance var cloner = GetClonerForValueType(); diff --git a/DeepCloner/Helpers/ReflectionHelper.cs b/DeepCloner/Helpers/ReflectionHelper.cs index 9ac8966..a290368 100644 --- a/DeepCloner/Helpers/ReflectionHelper.cs +++ b/DeepCloner/Helpers/ReflectionHelper.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Reflection; @@ -50,8 +52,33 @@ public static FieldInfo[] GetAllFields(this Type t) return t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); #endif } - - public static PropertyInfo[] GetPublicProperties(this Type t) + + /// + /// Returns all fields declared on the specified type and its base types. + /// + /// + internal static FieldInfo[] GetAllFieldsIncludingBaseTypes(this Type t) + { + var fields = new List(); + Type currentType = t; + do + { + fields.AddRange(currentType.GetAllFields()); + currentType = currentType.BaseType(); + } + while (currentType != null); + return fields.ToArray(); + } + + /// + /// Indicates whether the field type is or . + /// + internal static bool IsPropertyChangeEventHandler(this FieldInfo f) + { + return f.FieldType == typeof(PropertyChangingEventHandler) || f.FieldType == typeof(PropertyChangedEventHandler); + } + + public static PropertyInfo[] GetPublicProperties(this Type t) { #if NETCORE return t.GetTypeInfo().DeclaredProperties.ToArray();