某些类型的对象不适合被克隆,所以我们马上就知道永远不会有一种通用方法适用于所有情况。首先你需要知道类型可以被克隆。它需要有一个默认构造函数来做一件事。以及实际数据,而不是按需获取。
对于深度克隆,您会遇到额外的问题,这些问题在前面不一定会很明显。您如何处理具有不可克隆值的字段?您如何区分仅作为隐藏字段代理的属性与执行各种读取或写入操作的属性? event会员你们是怎么处理的?有许多常见结构会干扰您的克隆过程。
让我们暂时假设您要克隆的类型没有这些问题,图表中的任何对象也没有。您想创建一个可以处理基础的递归克隆方法。
在这种情况下,您只需要递归复制字段值,完全忽略属性。对于您复制的每个值 - 包括第一个 - 检查类型,如果它是您可以按值复制的东西(null 值,所有值类型,包括结构和一些不变类型,如 string),然后递归地克隆其余部分。
假设您没有遇到没有默认构造函数的对象,您可以使用Activator.CreateInstance() 来启动每个对象克隆。
您可以用大约 25 行代码完成一个简单的实现。这是一个糟糕的实现,仅用于演示目的,永远不要在生产中使用:
static T DeepClone<T>(T instance)
where T : class, new()
{
var visited = new Dictionary<object, object>();
object DoClone(object inst)
{
if (inst is null)
return null;
if (visited.TryGetValue(inst, out var prev))
return prev;
var type = inst.GetType();
var result = visited[inst] = Activator.CreateInstance(type);
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var field in fields)
{
var value = field.GetValue(inst);
if (field.FieldType.IsValueType || field.FieldType == typeof(string))
field.SetValue(result, value);
else
field.SetValue(result, DoClone(value));
}
return result;
}
return (T)DoClone(instance);
}
标准免责声明:它不漂亮,没有经过很好的测试,并且几乎可以保证在最不方便的时候破坏你。不处理任何类型的数组或集合。可能对儿童或小动物有害。醉酒时请勿操作。