克隆不同对象属性的最佳方法 [英] Best way to clone properties of disparate objects

查看:17
本文介绍了克隆不同对象属性的最佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an MVC3 application that needs to sync view models with database models. I found myself writing way too much code to copy properties back and forth between the different objects. I avoided this where I could simply subclass the data model, but at other times, I found that too restricting.

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

I developed a few extension methods on Object to support shallow cloning of properties with similar names, and this has worked rather well. However, I'm wondering if there is a more efficient means to accomplish the same thing. So I guess this is asking for peer review and options to improve upon this code.

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

UPDATE: I've found it better to handle related tables explicitly. Testing for IsVirtual will prevent relations from being inadvertently affected during cloning. See updated CloneMatching method. The others explicitly state which properties to update or exclude.

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;
    }
}

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

Here is an example of how I use it to map a view model to the data model.

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

推荐答案

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

You may consider using Object.MemberwiseClone method.

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

The MemberwiseClone method creates a shallow copy by creating a new object, and then copying the nonstatic fields of the current object to the new object. (docs.microsoft)

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

The method is protected. It means that you have to implement the Clone method in your classes. To make things even more fance you can add ICloneable to your classes as well.

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

这篇关于克隆不同对象属性的最佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆