如何将一个对象类型的对象深度复制到共享继承结构的另一个对象类型
本文关键字:类型 一个对象 共享 继承 结构 对象 深度 复制 | 更新日期: 2023-09-27 18:16:11
我目前正在为HL7消息构建对象模型。不深入研究这些,我们的基本结构看起来像这样:
- 基础对象
- 中介对象
- DeepMessage1
- DeepMessage2
消息1 - Message2
- 中介对象
我想有一个深度复制/克隆,将所有类似的属性从DeepMessage1复制到DeepMessage2或Message1或Message2。
public class BaseObject
{
PersonName Name; //A personName includes a first name and last name.
}
public class IntermediaryObject : BaseObject
{
Accident accident; //An accident codes and a description.
}
public class Message1 : BaseObject
{
//this class doesn't actually contain any special handling, just used for
//easy understanding for the API
}
public class Message2 : BaseObject
{
DateTime AdmissionDate; //Note the admission date is also contained in
//DeepMessage1, but not DeepMessage2
}
public class DeepMessage1 : IntermediaryObject
{
DateTime AdmissionDate; //Note this property is also contained in Message2 and
//needs to be copied
}
public class DeepMessage2 : IntermediaryObject
{
DateTime DischargeDate;
}
考虑到这个结构,我希望能够创建一个对象与另一个对象共享的每个属性的深度副本。另一个问题是一个很好的开始,但最终我不能使用反射,因为那是浅克隆,而序列化需要完全相同的对象。
我最终得到了这段代码,但它只执行了一个浅层复制。
public T Copy<T>() where T : new()
{
T destination = new T();
if (destination is HL7Message)
{
foreach (var destinationProperty in destination.GetType().GetProperties())
{
foreach (var sourceProperty in this.GetType().GetProperties())
{
if (destinationProperty.Name.Equals(sourceProperty.Name))
{
destinationProperty.SetValue(destination, destinationProperty.GetValue(this, null), null);
}
}
}
return destination;
}
else
{
throw new InvalidOperationException("The destination copy type is not an HL7Message object");
}
}
我希望在我的if (destinationProperty.Name.Equals(sourceProperty.Name))
块中,我可以尝试在特定基本类型(我的库中的所有对象扩展)的任何属性上调用Copy。但是,我无法使该部分中的Copy工作,因为我无法在运行时确定T。
我是否只需要为特定对象设置一个单独的Copy类型,并让消息使用Copy,或者有一种方法可以做到这一点,这是如此该死的疯狂?
这是一个在对象之间复制属性的完整工具,看一下:
https://github.com/AutoMapper/AutoMapper/wiki为了解决这个问题,我最终采用了两层方法。我并不是断言devman提到的地图不可能起作用,但由于时间有限,我无法探索他的解决方案。
首先,我的所有对象都扩展了相同的基对象(在本例中为BaseLibraryClass)。我最初这样做是因为每个类都要继承INotifyPropertyChanged。为了处理引发属性更改,我创建了一个基对象,所有对象都继承自它。在这个基类上,我还添加了一个抽象的DeepCopy()方法。每个对象都将通过创建自身的新实例并为其赋值来覆盖DeepCopy()方法,或者在自定义属性的情况下,对这些属性调用DeepCopy()。
Class Cat : BaseLibraryClass
{
public string Name;
public Collar MyCollar;
public override object DeepCopy()
{
Cat destination = new Cat();
Cat.Name = Name;
Cat.MyCollar = MyCollar.DeepCopy();
}
}
Class Collar { ... }
现在我把它与我原来问题中反射循环的修改版本结合起来。所有我希望能够做这种复制的对象都继承了相同的基类。在示例中,是一个BaseCopyObject。
public T CopyObject<T>() where T : new()
{
T destination = new T();
if (destination is BaseCopyObject)
{
foreach (var destinationProperty in destination.GetType().GetProperties()) //iterate through the properties of the destination object.
{
foreach (var sourceProperty in this.GetType().GetProperties()) // iterate through the properties of the source object to determine if the property names match. If they do, copy the value.
{
//If we have one of our BaseCopyObjects, then set the value with the DeepCopy() method of that object.
if (destinationProperty.Name.Equals(sourceProperty.Name))
{
if (typeof(BaseLibraryClass).IsAssignableFrom(destinationProperty.PropertyType))
{
BaseCopyObject var = (BaseLibraryClass)sourceProperty.GetValue(this, null);
if (var != null)
{
destinationProperty.SetValue(destination, var.DeepCopy(), null);
}
break;
}
//If we have a list, get the list and iterate through the list objects.
else if (typeof(IList).IsAssignableFrom(destinationProperty.PropertyType))
{
IList destinationList = (IList)destinationProperty.GetValue(destination, null);
destinationList.Clear();
IList sourcelist = (IList)destinationProperty.GetValue(this, null);
if (sourcelist != null)
{
foreach (object listItem in sourcelist)
{
if (listItem is Base)
{
BaseLibraryClass n = (BaseLibraryClass)listItem;
destinationList.Add(n);
}
}
}
break;
}
//Finally we get to normal properties. Set those.
else
{
destinationProperty.SetValue(destination, destinationProperty.GetValue(this, null), null);
break;
}
}
}
}
return destination;
}
else
{
throw new InvalidOperationException("The destination copy type is not an BaseLibraryClass object");
}
}