我目前正在为HL7消息构建对象模型。没有深入研究,我们的基本结构看起来与此相似:
我希望有一个深层复制/克隆,它将所有类似的属性从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;
}
考虑到这种结构,我希望能够创建一个对象与另一个对象共享的每个属性的深层副本。 This other question是一个非常好的开始,但最终我无法使用反射,因为这是浅层克隆,序列化需要完全相同的对象。
我最终得到了这段代码,但它只执行浅拷贝。
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。但是,由于无法在运行时确定T,我无法在该部分中使用Copy。
我是否只需要为特定对象设置单独的Copy类型,并让Messages使用Copy或者有没有办法做到这一点真是太疯狂了?
答案 0 :(得分:3)
这是一个用于在对象之间复制属性的完整工具,请看一下:
答案 1 :(得分:1)
为了解决这个问题,我最终采用了两层方法。我并没有断言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");
}
}