【问题标题】:Best way to clone properties of disparate objects克隆不同对象属性的最佳方法
【发布时间】:2012-12-22 13:00:52
【问题描述】:

我有一个需要将视图模型与数据库模型同步的 MVC3 应用程序。我发现自己编写了太多代码来在不同对象之间来回复制属性。我避免了这种情况,因为我可以简单地对数据模型进行子类化,但在其他时候,我发现这太限制了。

我在 Object 上开发了一些扩展方法来支持对具有相似名称的属性进行浅层克隆,并且效果很好。但是,我想知道是否有更有效的方法来完成同样的事情。所以我想这是要求同行评审和改进此代码的选项。

更新: 我发现明确处理相关表会更好。对 IsVirtual 的测试将防止在克隆期间无意中影响关系。请参阅更新的 CloneMatching 方法。其他人明确说明要更新或排除哪些属性。

public static class CustomExtensions
{
   public static T CloneMatching<T, S>(this T target, S source)
       where T : class
       where S : class
    {
        if (source == null)
        {
            return target;
        }
        Type sourceType = typeof(S);
        Type targetType = typeof(T);
        BindingFlags flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance;

        PropertyInfo[] properties = sourceType.GetProperties();
        foreach (PropertyInfo sPI in properties)
        {
            PropertyInfo tPI = targetType.GetProperty(sPI.Name,flags);
            if (tPI != null && tPI.PropertyType.IsAssignableFrom(sPI.PropertyType) && !tPI.PropertyType.IsVirtual)
            {
                tPI.SetValue(target, sPI.GetValue(source, null), null);
            }
        }
        return target;
    }

    public static T CloneProperties<T, S>(this T target, S source, string[] propertyNames)
       where T : class
       where S : class
    {
        if (source == null)
        {
            return target;
        }
        Type sourceType = typeof(S);
        Type targetType = typeof(T);
        BindingFlags flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance;

        PropertyInfo[] properties = sourceType.GetProperties();
        foreach (PropertyInfo sPI in properties)
        {
            if (propertyNames.Contains(sPI.Name))
            {
                PropertyInfo tPI = targetType.GetProperty(sPI.Name, flags);
                if (tPI != null && tPI.PropertyType.IsAssignableFrom(sPI.PropertyType))
                {
                    tPI.SetValue(target, sPI.GetValue(source, null), null);
                }
            }
        }
        return target;
    }
    public static T CloneExcept<T, S>(this T target, S source, string[] propertyNames)
       where T : class
       where S : class
    {
        if (source == null)
        {
            return target;
        }
        Type sourceType = typeof(S);
        Type targetType = typeof(T);
        BindingFlags flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance;

        PropertyInfo[] properties = sourceType.GetProperties();
        foreach (PropertyInfo sPI in properties)
        {
            if (!propertyNames.Contains(sPI.Name))
            {
                PropertyInfo tPI = targetType.GetProperty(sPI.Name, flags);
                if (tPI != null && tPI.PropertyType.IsAssignableFrom(sPI.PropertyType))
                {
                    tPI.SetValue(target, sPI.GetValue(source, null), null);
                }
            }
        }
        return target;
    }
}

这是我如何使用它将视图模型映射到数据模型的示例。

DataSession.Quote.CloneProperties(viewModel,
                new[] {"PaymentType","CardHolder","CardHolderZip","CardNumber","CardExp","CVC",
                          "AccountHolder","AccountHolderZip","ABA","Account",
                          "AccuracyAgreement","PrivacyTermsAgreement","ElectronicSignatureAgreement"});

【问题讨论】:

  • AutoMapper 或类似的东西对您没有帮助。 automapper.org
  • 谢谢,我去看看!
  • 这是我们用来解决OP情况的方法。 +1
  • 那肯定会做我想要的。表现如何?我浏览了它的代码,这对于我需要的东西来说似乎有点矫枉过正。
  • 我不是 automapper 方面的专家。这是一篇旧帖子,但也许它可能会有所启发,否则可能会发布另一个问题。 stackoverflow.com/a/6474397/1099260

标签: c# reflection cloning


【解决方案1】:

您可以考虑使用Object.MemberwiseClone 方法。

MemberwiseClone 方法通过创建一个新对象来创建浅拷贝,然后将当前对象的非静态字段复制到新对象中。 (docs.microsoft)

方法受到保护。这意味着你必须在你的类中实现Clone 方法。为了让事情更有趣,您也可以将ICloneable 添加到您的课程中。

class MyClass: ICloneable
{
    // all your code
    MyClass Clone()
    {
        return (MyClass)this.MemberwiseClone();
    }
}

【讨论】:

  • 这将返回一个与原始对象相同类型的对象。我想要的是跨不同类型的对象克隆同名的属性。
  • 考虑这个页面,其中视图模型封装了人、车辆和驾驶历史信息。在后端,这些被拆分为单独的实体,但以单一形式呈现给用户。 demoagent.com/applicant
猜你喜欢
  • 2016-08-05
  • 2019-01-21
  • 2015-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多