gpt4 book ai didi

c# - 对象深度克隆实现

转载 作者:行者123 更新时间:2023-11-30 14:30:57 25 4
gpt4 key购买 nike

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

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;
}
}

效果很好。但是如果要克隆的对象和它的引用类型字段有相互引用,这段代码会导致无限循环。例如

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; }
}

有谁知道如何执行此任务?它应该按字面意思实现,不允许有任何变化(这是一个实习)。非常感谢任何提示!

最佳答案

深度克隆对象的一个​​老技巧是对它们进行序列化和反序列化,从而创建新的实例。

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

我广泛使用 Newtonsoft.Json,它有一个内置的解决方案来解决您的问题。默认情况下,它会检测一个对象是否已经被序列化并抛出异常。但是,您可以将其配置为序列化对对象的引用以避开循环引用。它不是在线序列化对象,而是序列化对该对象的引用,并保证对对象的每个引用只序列化一次。

此外,默认情况下仅序列化公共(public)字段/属性。还有一个用于序列化私有(private)字段的附加设置。

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);
}

因此您可以“作弊”并使用这样的代码,或者复制它的工作原理来实现保留引用的克隆。你举的 parent / child 的例子只是克隆困难的一种方式。 1对多是另一个。

关于c# - 对象深度克隆实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21591544/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com