使用反射在Silverlight扩展方法中实现深拷贝?

3

我正试图找到一个通用的扩展方法,使用反射创建一个对象的深拷贝,以便在Silverlight中使用。在Silverlight中使用序列化进行深拷贝并不是很好,因为它在部分信任中运行且BinaryFormatter不存在。我也知道对于克隆来说,使用反射比序列化更快。

最好有一个方法可以复制公共的、私有的和受保护的字段,并且是递归的,以便可以复制对象中的对象,并且还能处理集合、数组等。

我已经在网上搜索过了,只能找到使用反射的浅拷贝实现。我不明白为什么,因为你可以使用MemberwiseClone,所以对我来说那些实现是无用的。

谢谢。

3个回答

3

所需名称空间:

using System.Reflection;
using System.Collections.Generic;

方法:

    private readonly static object _lock = new object();

    public static T cloneObject<T>(T original, List<string> propertyExcludeList)
    {
        try
        {
            Monitor.Enter(_lock);
            T copy = Activator.CreateInstance<T>();
            PropertyInfo[] piList = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            foreach (PropertyInfo pi in piList)
            {
                if (!propertyExcludeList.Contains(pi.Name))
                {
                    if (pi.GetValue(copy, null) != pi.GetValue(original, null))
                    {
                        pi.SetValue(copy, pi.GetValue(original, null), null);
                    }
                }
            }
            return copy;
        }
        finally
        {
            Monitor.Exit(_lock);
        }
    }

这与Silverlight无关,只是普通的反射。

如所写,它仅适用于具有无参构造函数的对象。要使用需要构造函数参数的对象,您需要传递一个带有参数的object[],并使用Activator.CreateInstance方法的不同重载,例如:

T copy = (T)Activator.CreateInstance(typeof(T), initializationParameters);

propertyExcludeList参数是您希望从副本中排除的属性名称列表。如果您想复制所有属性,请传递一个空列表,例如。

new List<string>()

我收到了 System.ArgumentException was unhandled by user code Message=Property set method not found. 的错误信息。 - Peter Lee
5
这是一个浅拷贝。如果需要深度拷贝,就需要递归地检查属性是否为集合类型。请注意,在翻译过程中不改变原意,并尽量让翻译易于理解。 - xr280xr

3

对于数据契约对象,我们在Silverlight中使用以下帮助方法进行深层克隆:

public static T Clone<T>(T source)
        {

            DataContractSerializer serializer = new DataContractSerializer(typeof(T));
            using (MemoryStream ms = new MemoryStream())
            {
                serializer.WriteObject(ms, source);
                ms.Seek(0, SeekOrigin.Begin);
                return (T)serializer.ReadObject(ms);
            }
        }

使用方法如下:

var clone = CloneHelper.Clone<MyDTOType>(dtoVar);

这是基于序列化的,它能在非可序列化类上工作吗? - Kira
快速问题,这个如何处理数组和列表?它会复制数组/列表的引用吗?还是会在新的引用下重建数组/列表?换句话说,如果将带有列表的类A复制到B中,那么编辑B是否也会编辑A的列表? - Krythic

2

您不能直接使用普通的.NET反射吗?将对象序列化到MemoryStream,然后将其反序列化回来。这将创建一个深层副本(最终使用反射),并且不需要您编写太多代码:

T DeepCopy<T>(T instance)
{
  BinaryFormatter formatter=new BinaryFormatter();

  using(var stream=new MemoryStream())
  {
    formatter.Serialize(stream, instance);
    stream.Position=0;

    return (T)formatter.Deserialize(stream);
  }
}

1
不,Silverlight中不存在BinaryFormatter。 - Didier A.
2
这对于用户控件,如非可序列化对象是不起作用的! - IremadzeArchil19910311

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接