【问题标题】:My deep copy isn't doing a real deep copy我的深拷贝没有做真正的深拷贝
【发布时间】:2012-06-19 20:36:29
【问题描述】:

我有一个班级,我正在尝试对其进行深拷贝。此类的成员之一是“MeshContainers”,它是 MeshContainerCollection 的一个实例。

MeshContainerCollection 继承自我的 SceneObjectCollection 类,该类继承自 List

我注意到源对象在 meshcontainercollection 中有 1 个项目,而克隆对象有 0 个项目。 在逐步执行 DeepCopy 过程时,我注意到当我尝试获取 MeshContainerCollection 的字段时,它没有找到任何字段。 现在 MeshContainerCollection 没有任何直接字段(只有继承的字段)所以我认为这是问题所在。

但我使用:

FieldInfo[] fields = type.GetFields(BindingFlags.Public |
        BindingFlags.NonPublic | BindingFlags.Instance);

哪个(afaik)也应该返回私有继承成员。 我查看了现有的 BindingFlags,但无法确定是否还有另一个 BindingFlag 应该用于获取继承的私有字段。

有人能告诉我如何做一个真正的深拷贝吗?

我正在使用的深度复制方法:

private 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 = FormatterServices.GetUninitializedObject(obj.GetType());
        FieldInfo[] fields = type.GetFields(BindingFlags.Public |
                    BindingFlags.NonPublic | BindingFlags.Instance);
        foreach (FieldInfo field in fields)
        {
            object fieldValue = field.GetValue(obj);
            if (fieldValue == null)
                continue;
            field.SetValue(toret, Process(fieldValue));
        }

        return toret;
    }
    else
        throw new ArgumentException("Unknown type");
}

EDIT1:我不喜欢通过序列化而是通过反射来做到这一点。

【问题讨论】:

  • 最简单的deep copy implementation I've seen,它可能会对你有所帮助。 :)
  • @Trustme-I'maDoctor 虽然需要可序列化的类 :)
  • 更新帖子,见帖子结尾
  • @romkyns 没错,但它简短而优雅:) 所以如果你只能在所有课程上使用[Serializable],我肯定会使用这个解决方案。
  • @romkyns,我在帖子中想说的是字段是空的。

标签: c# .net


【解决方案1】:

GetFields documentation中所述,

不返回基类的私有字段。

试试这个方法:

public static IEnumerable<FieldInfo> GetAllFields(this Type type)
{
    IEnumerable<FieldInfo> fields = type.GetFields(
        BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

    if (type.BaseType == null)
        return fields;
    else
        return GetAllFields(baseType).Concat(fields);
}

(您可能想重写它以避免所有可枚举和串联,但您明白了)

【讨论】:

  • 这几乎给了我一个 stackoverflow 异常。我注意到它贯穿了很多“Reflection.Pointer”实例。不知道是不是这个原因……
【解决方案2】:

您可以实现此目的的方法之一是序列化对象,然后将其反序列化.. 编写一个函数来做同样的事情.. 仅供参考,您的班级需要为此标记[Serializable]..

那里有一些库做同样的事情。Copyable 就是其中之一。我建议不要尝试重新发明轮子,而是在这个库上建立,因为有太多的边缘条件需要处理你的深拷贝..也许你也可以向作者提交补丁..

【讨论】:

  • 更新帖子,见帖子结尾
  • 谢谢,我会试试的。我会在这里发布结果。
  • 这并没有解决我的问题。我不得不更改对象初始化程序以使用 FormatterServices.GetUninitializedObject(obj.GetType());因为我没有无参数构造函数,即使这样它也返回了一个空的 MeshContainerCollection。
猜你喜欢
  • 2012-04-12
  • 2015-01-13
  • 2011-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多