【问题标题】:How can I deep copy an object of one object type to another object type that share an inheritance structure如何将一种对象类型的对象深度复制到共享继承结构的另一种对象类型
【发布时间】:2012-01-10 05:02:05
【问题描述】:

我目前正在为 HL7 消息构建对象模型。如果不深入研究,我们的基本结构类似于:

  • 基础对象
    • 中间对象
      • DeepMessage1
      • DeepMessage2
    • 消息1
    • 消息2

我想要一个深拷贝/克隆,它将所有类似属性从 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。但是,我无法让该部分中的 Copy 工作,因为我无法在运行时确定 T。

我是否只需要为特定对象创建一个单独的副本类型并让消息使用该副本,还是有一种方法可以做到这一点,这太疯狂了?

【问题讨论】:

  • 如果您要复制的属性是 DateTime,则深复制/浅复制无关紧要 DateTime 是值类型,值的副本,因为没有对复制的引用。

标签: c# inheritance clone


【解决方案1】:

这是一个完整的对象间属性复制工具,看看:

https://github.com/AutoMapper/AutoMapper/wiki

【讨论】:

  • 我正在查看自动映射器,我是否需要将说 AdmissionDate 映射到 AdmissionDate 以及将 Message2 映射到 DeepMessage1,或者由于它们共享属性名称,所以该映射是隐含的?他们的示例似乎暗示您必须映射不是标准类型的每个对象。对于像我们这样大的图书馆来说,这会使映射有点不合理。
  • 您可以通过几行代码轻松开发一个忽略大小写的自定义值解析器。
  • 抱歉,问题不在于大小写不同。那是一个错字。相反,问题在于映射过程,以及我是否必须将 AdmissionDate 映射到 AdmissionDate 以及将 Message2 映射到 DeepMessage1(两者都包含 AdmissionDate)。考虑到我必须映射的对象数量,这是对地图长度的关注。
【解决方案2】:

为了解决这个问题,我最终采用了 2 层方法。我没有断言 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");
    }
}

【讨论】:

    猜你喜欢
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    • 2012-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多