我写了一个漂亮的方法来深度复制任何对象。它通过在实例内的任何引用类型字段上递归调用MemberwiseClone()
来实现。此方法适用于我关心的任何对象,包括层次结构关系对象。该方法还具有过去访问的字典,因此避免了不必要的重复工作。
然而,我遇到的问题是,只有在需要克隆时对象不是绑定到WPF / MVVM的数据时,此方法才有效。当数据绑定并调用方法时,我会遇到堆栈溢出异常,因为(我假设)INotifyPropertyChanged.PropertyChanged
事件和WPF框架之间建立了链接。递归调用然后尝试复制整个对象世界,包括AppDomain
和低级Pointer对象,这些对象看起来是链接的,并且几乎无限远(无论如何,VS2012都可以处理。)
我怀疑我是否需要深度复制一个可以追溯到AppDomain
开头的对象图...有一种聪明的方法让我的复制方法“停止”到达某个时候边界?我还想过在数据绑定之前简单地复制对象,但我不确定这是一个可行的选择,而且它相当愚蠢。我只想要一个简单的深层复制解决方案,该解决方案适用于不可序列化的类型,但也通过INotifyPropertyChanged
进行数据绑定。
该方法的实施:
private static object Clone(object instance, IDictionary<object, object> visitGraph)
{
var instanceType = instance.GetType();
Debug.WriteLine(instanceType.Name);
object clonedInstance = null;
if (visitGraph.ContainsKey(instance))
{
clonedInstance = visitGraph[instance];
}
else
{
const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance;
var memberwiseCloneMethod =
instanceType.GetMethods(flags).Single(x => x.Name == "MemberwiseClone" &&
!x.GetParameters().Any());
clonedInstance = memberwiseCloneMethod.Invoke(instance, null);
visitGraph.Add(instance, clonedInstance);
var allReferenceTypeProperties = clonedInstance.GetType().GetAllFields()
.Where(
x =>
!x.FieldType.IsValueType
&& x.FieldType != typeof (string));
foreach (var field in allReferenceTypeProperties)
{
var existingFieldValue = field.GetValue(instance);
if (existingFieldValue != null)
{
var clonedFieldValue = Clone(existingFieldValue, visitGraph);
field.SetValue(clonedInstance, clonedFieldValue);
}
}
}
return clonedInstance;
}
public static IEnumerable<FieldInfo> GetAllFields(this Type type)
{
const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance;
var fields = type.GetFields(flags);
foreach (var field in fields)
{
yield return field;
}
if (type.BaseType != null)
{
foreach (var field in GetAllFields(type.BaseType))
{
yield return field;
}
}
}
public static object Copy(this object instance)
{
if (instance == null) throw new ArgumentNullException("instance");
var visitGraph = new Dictionary<object, object>();
var clonedInstance = Clone(instance, visitGraph);
return clonedInstance;
}
答案 0 :(得分:0)
我正在用快捷解决方案回答我自己的问题。我更喜欢永久的解决方案,但我没有奢侈品。
我将我的深度克隆方法修改为浅(而不是深)复制EventHandler对象。对象不再是真正的深度克隆,但这对我的应用程序来说不是问题。不过,我想要一个适用于所有情况的解决方案。