复杂第三方的深拷贝 Objects/Classes
Deep Copy of Complex Third Party Objects/Classes
我一直在从事一个使用 PDFView4Net 创建 PDF 表单的项目。虽然库通常很好,但表单创建器是原始的并且在处理表单字段(即文本框、复选框等)时缺乏基本功能(例如 copy/paste、对齐、格式化等)。
问题:我一直在扩展字段对象的功能并在 copy/paste 上被绊倒了。为此,我需要对象的深层副本,不引用任何原始对象。我给供应商发了电子邮件,要求他们提供有关复制这些对象的推荐方法的信息,他们回复说我需要手动制作每个 属性 的副本... beats head on desk。这些是大型 classes,具有多个嵌入的 classes 作为属性,以及 UI 元素。
问题:有没有好的方法可以对不需要序列化的复杂对象执行深拷贝,不需要访问或更改源 classes 并且不需要默认构造函数?
我有什么tried/reviewed:
我研究了各种方法来制作一个对象的深拷贝,并一一丢弃:
- 手动,属性 由 Painstaking 属性:我尝试使用 7 个字段对象 (PDFTextBoxField) 中的第一个进行此操作,但它很快就失去了对同样是不同类型的众多属性的控制class 的。最后,我仍然对原始对象有挥之不去的引用,在那里它创建了一个浅拷贝而不是预期的深拷贝。
- 序列化:classes 未标记为可序列化,供应商也不会对此进行更改。我问他们,他们说不。
- ICloneable:需要由供应商实施。
- AutoMapper:这似乎是为了将数据从一种或多种对象类型复制到另一种对象类型。我正在使用的对象是同一类型。如果这是最好的解决方案,我不反对使用它。
- Emit Mapper:该项目似乎已被放弃。
- MemberwiseClone:做一个浅拷贝,而不是我正在寻找的深拷贝,尽管当提问者特别要求深拷贝时,在大量其他 post 上建议这样做。
- Value Injecter:我在 CodePlex 上从 ValueInjecter 实现了 FastDeepCloneInjection,但是大多数需要从中注入的 classes 没有创建新的 0 参数构造函数副本的实例。 ValueInjecter 不允许跳过某些属性,或者我会跳过没有默认构造函数的项目并将它们设置为 null(默认值)。我 运行 马上就用第一个 class 加入了这个。为了尝试解决这个问题,我创建了一个从原始文件继承的包装器 class,并将原始文件转换为包装器(反之亦然 return),但我认为这不是一个好的解决方案.
编辑: 我真的不觉得这个问题是重复的。我广泛搜索了解决方案,包括标记为 duplicate/original 的 post,但未能找到令人满意的解决方案。如前所述,我无权更改我需要复制的 classes。这会打折 DataContractSerializer、BinaryFormatter 和任何其他类型的序列化。这也打折了我看到的使用 Activator.CreateInstance 的反射示例,因为我需要复制的 classes 中大约 95% 没有采用 0 个参数的构造函数。这与我 运行 使用 ValueInjecter 时遇到的问题相同。这也使用 ICloneable 打折。
我会为此使用 AutoMapper。考虑以下 class 定义:(注意 private ctor)
public class Parent
{
public string Field1 { get; set; }
public Level1 Level1 { get; set; }
public static Parent GetInstance()
{
return new Parent() { Field1 = "1", Level1 = new Level1 { Field2 = "2", Level2 = new Level2() { Field3 = "3"}}};
}
private Parent() { }
}
public class Level1
{
public string Field2 { get; set; }
public Level2 Level2 { get; set; }
}
public class Level2
{
public string Field3 { get; set; }
}
然后您可以根据需要将 AutoMapper 设置为深度克隆:
[TestMethod]
public void DeepCloneParent()
{
Mapper.CreateMap<Parent, Parent>();
Mapper.CreateMap<Level1, Level1>();
Mapper.CreateMap<Level2, Level2>();
var parent = Parent.GetInstance();
var copy = Mapper.Map<Parent, Parent>(parent);
Assert.IsFalse(copy == parent);//diff object
Assert.IsFalse(copy.Level1 == parent.Level1);//diff object
Assert.IsFalse(copy.Level1.Level2 == parent.Level1.Level2);//diff object
Assert.AreEqual("1", copy.Field1);
Assert.AreEqual("2", copy.Level1.Field2);
Assert.AreEqual("3", copy.Level1.Level2.Field3);
}
我一直在从事一个使用 PDFView4Net 创建 PDF 表单的项目。虽然库通常很好,但表单创建器是原始的并且在处理表单字段(即文本框、复选框等)时缺乏基本功能(例如 copy/paste、对齐、格式化等)。
问题:我一直在扩展字段对象的功能并在 copy/paste 上被绊倒了。为此,我需要对象的深层副本,不引用任何原始对象。我给供应商发了电子邮件,要求他们提供有关复制这些对象的推荐方法的信息,他们回复说我需要手动制作每个 属性 的副本... beats head on desk。这些是大型 classes,具有多个嵌入的 classes 作为属性,以及 UI 元素。
问题:有没有好的方法可以对不需要序列化的复杂对象执行深拷贝,不需要访问或更改源 classes 并且不需要默认构造函数?
我有什么tried/reviewed: 我研究了各种方法来制作一个对象的深拷贝,并一一丢弃:
- 手动,属性 由 Painstaking 属性:我尝试使用 7 个字段对象 (PDFTextBoxField) 中的第一个进行此操作,但它很快就失去了对同样是不同类型的众多属性的控制class 的。最后,我仍然对原始对象有挥之不去的引用,在那里它创建了一个浅拷贝而不是预期的深拷贝。
- 序列化:classes 未标记为可序列化,供应商也不会对此进行更改。我问他们,他们说不。
- ICloneable:需要由供应商实施。
- AutoMapper:这似乎是为了将数据从一种或多种对象类型复制到另一种对象类型。我正在使用的对象是同一类型。如果这是最好的解决方案,我不反对使用它。
- Emit Mapper:该项目似乎已被放弃。
- MemberwiseClone:做一个浅拷贝,而不是我正在寻找的深拷贝,尽管当提问者特别要求深拷贝时,在大量其他 post 上建议这样做。
- Value Injecter:我在 CodePlex 上从 ValueInjecter 实现了 FastDeepCloneInjection,但是大多数需要从中注入的 classes 没有创建新的 0 参数构造函数副本的实例。 ValueInjecter 不允许跳过某些属性,或者我会跳过没有默认构造函数的项目并将它们设置为 null(默认值)。我 运行 马上就用第一个 class 加入了这个。为了尝试解决这个问题,我创建了一个从原始文件继承的包装器 class,并将原始文件转换为包装器(反之亦然 return),但我认为这不是一个好的解决方案.
编辑: 我真的不觉得这个问题是重复的。我广泛搜索了解决方案,包括标记为 duplicate/original 的 post,但未能找到令人满意的解决方案。如前所述,我无权更改我需要复制的 classes。这会打折 DataContractSerializer、BinaryFormatter 和任何其他类型的序列化。这也打折了我看到的使用 Activator.CreateInstance 的反射示例,因为我需要复制的 classes 中大约 95% 没有采用 0 个参数的构造函数。这与我 运行 使用 ValueInjecter 时遇到的问题相同。这也使用 ICloneable 打折。
我会为此使用 AutoMapper。考虑以下 class 定义:(注意 private ctor)
public class Parent
{
public string Field1 { get; set; }
public Level1 Level1 { get; set; }
public static Parent GetInstance()
{
return new Parent() { Field1 = "1", Level1 = new Level1 { Field2 = "2", Level2 = new Level2() { Field3 = "3"}}};
}
private Parent() { }
}
public class Level1
{
public string Field2 { get; set; }
public Level2 Level2 { get; set; }
}
public class Level2
{
public string Field3 { get; set; }
}
然后您可以根据需要将 AutoMapper 设置为深度克隆:
[TestMethod]
public void DeepCloneParent()
{
Mapper.CreateMap<Parent, Parent>();
Mapper.CreateMap<Level1, Level1>();
Mapper.CreateMap<Level2, Level2>();
var parent = Parent.GetInstance();
var copy = Mapper.Map<Parent, Parent>(parent);
Assert.IsFalse(copy == parent);//diff object
Assert.IsFalse(copy.Level1 == parent.Level1);//diff object
Assert.IsFalse(copy.Level1.Level2 == parent.Level1.Level2);//diff object
Assert.AreEqual("1", copy.Field1);
Assert.AreEqual("2", copy.Level1.Field2);
Assert.AreEqual("3", copy.Level1.Level2.Field3);
}