对象深层克隆实现 [英] Object deep clone implementation

查看:63
本文介绍了对象深层克隆实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须实现通用扩展deepclone方法,该方法可与任何引用类型实例一起使用以获取其深层副本。我将其实现为以下

I have to implement generic extention deepclone method which can be used with any reference type instance to get its deep copy. I implement it as the following

static class ClassCopy
{
    static public T DeepClone<T> (this T instance)
    {
        if (instance == null) return null;
        var type = instance.GetType();
        T copy;
        var flags = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic |
                    BindingFlags.Instance;

        var fields = type.GetFields(flags);

        // If type is serializable - create instance copy using BinaryFormatter
        if (type.IsSerializable)
        {
            using (var stream = new MemoryStream())
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(stream, instance);
                stream.Position = 0;
                copy = (T) formatter.Deserialize(stream);
            }

            // Copy all fiels  which are not marked as serializable 
            foreach (var field in fields)
            {
                if (!field.IsNotSerialized) continue;
                var value = field.GetValue(instance);

                //Recursion!!!
                //for each embedded object also create deep copy
                value = value != null  ? value.DeepClone() : value;
                field.SetValue(copy, value);
            }
        }
        else
        {
            // If type is not serializable - create instance copy using Activator
            //(if there is default constructor)
            // or FormatterServices ( if there is no constractor)

            copy = CreateInstance<T>(type);
            foreach (var field in fields)
            {
                var value = field.GetValue(instance);

                //Recursion!!!
                value = value != null  ? value.DeepClone() : value;
                field.SetValue(copy, value);
            }
        }

        //Copy all properties 
        //In order to copy all backing fields  for auto-implemented properties

        var properties = type.GetProperties(flags|BindingFlags.SetProperty);
        foreach (var property in properties)
        {
            if (property.CanWrite)
            {
                var value = property.GetValue(instance);

                //Recursion!!!
                value = value != null ? value.DeepClone() : null;
                property.SetValue(copy, value);
            }
        }
        return copy;
    }

    private static T CreateInstance<T>(Type t) where T: class
    {
        T instance;
        var constructor = t.GetConstructor(Type.EmptyTypes);
        if (constructor != null)
        {
            instance = Activator.CreateInstance(t) as T;
            return instance;
        }
        instance = FormatterServices.GetUninitializedObject(t) as T;
        return instance;
    }
}

效果很好。但是,如果要克隆的对象及其引用类型字段具有相互引用,则此代码将导致无限循环。
例如

It works well. But if object to be cloned and its reference type fields have mutual references this code leads to infinite loops. e.g.

private static void Main(string[] args)
{
    var parent = new Parent();
    parent.Child = new Child();
    parent.Child.Parent = parent;
    //Infinite Loop!!!
    var parent1 = parent.DeepClone();
}

class Parent
{
    public Child Child { get; set; }
}
class Child
{
    public Parent Parent { get; set; }
}

有人知道如何实现此任务吗?应该从字面上实现它,并且不允许任何变化(这是一种实践)。非常感谢您提供的任何提示!

Does anyone has any idea how to implement this task? It should be implemented literally and no variations are allowed (it's a practicum). Thanks a lot for any tips!

推荐答案

您可以做的就是绕过 Dictionary 映射到其克隆的项目。现在该方法将如下所示:

What you can do is pass around a Dictionary of items mapped to their clones. Now the method will look like this:

静态私有T DeepClone< T> (此T实例,IDictionary< object,object> originalToAlreadyCloned),其中T:class

现在,您在<$ c $之后要做的第一件事c>如果(instance == null)返回null; ,检查 instance 是否存在于 originalToAlreadyCloned ,如果是,则将其返回。

Now the first thing you do after if (instance == null) return null;, is check if instance is present in originalToAlreadyCloned and if so, return it.

为了填充它,在

    $ b之后$ b
  1. copy =(T)formatter.Deserialize(stream);

  2. copy = CreateInstance< ; T>(类型);

  1. copy = (T) formatter.Deserialize(stream);
  2. copy = CreateInstance<T>(type);

调用 originalToAlreadyCloned.Add(instance,复制);

最后,提供一种新的顶级方法:

Finally, provide a new top-level method:

静态私有T DeepClone< T> (此T实例),其中T:类只需调用 DeepClone(instance,new Dictionary< object,object>());

顺便说一下, value = value!= null& value.GetType()。IsClass? value.DeepClone():null; 似乎是错误的。您的意思是,如果 value 不是类,请将其设置为null。但是,如果不是课程,则通常不能将其设置为null。我不确定您为什么不也克隆这些项目,以及为什么 DeepClone 仅限于类。

By the way, value = value != null && value.GetType().IsClass? value.DeepClone() : null; seems wrong. What you're saying is, if value is not a class, set it to null. But if it's not a class, you can't generally set it to null. I'm not sure why you don't just clone these items too, and why DeepClone is restricted to only classes.

这篇关于对象深层克隆实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆