Object deep clone implementation

夙愿已清 提交于 2019-12-06 01:39:11

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

static private T DeepClone<T> (this T instance, IDictionary<object, object> originalToAlreadyCloned) where T: class

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.

In order to populate it, after

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

call originalToAlreadyCloned.Add(instance, copy);

Finally, provide a new top-level method:

static private T DeepClone<T> (this T instance) where T: class that simply calls DeepClone(instance, new Dictionary<object, object>());

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.

An old trick for deep-cloning objects, is to serialize and de-serialize them, thereby creating new instances.

public T deepClone<T>(T toClone) where T : class
{
    string tmp = JsonConvert.SerializeObject(toClone);
    return JsonConvert.DeserializeObject<T>(tmp);            
}

I've worked extensively with Newtonsoft.Json and it has a built in solution to your problem. By default, it detects if an object has already be serialized and throws an exception. However, you can configure it to serialize references to object for getting around circular references. Instead of serializing objects in-line, it serializes a reference to that object and guarantees that every reference to an object is only serialized once.

Further, the default is to only serialize public fields/properties. There is an additional setting for serializing the private fields too.

public T deepClone<T>(T toClone) where T : class
{
    JsonSerializerSettings settings = new JsonSerializerSettings();
    settings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;

    DefaultContractResolver dcr = new DefaultContractResolver();
    dcr.DefaultMembersSearchFlags |= System.Reflection.BindingFlags.NonPublic;
    settings.ContractResolver = dcr;

    string tmp = JsonConvert.SerializeObject(toClone, settings);
    return JsonConvert.DeserializeObject<T>(tmp);
}

So you could either "cheat" and use code like this or copy how it works to implement a clone that preserves references. The example you gave of parent / child is just 1 way cloning is difficult. 1 to many is another.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!