如何通过匹配字段或属性名称来复制来自不同类的数据

时间:2010-09-12 20:22:12

标签: c# mvvm c#-4.0

我希望找到一种方法来获取具有相同属性的两个对象,并调用将属性值从一个对象复制到另一个对象。下面的示例假设我有一个A的实例,我想使用该实例的数据来水合新的实例或C(为了保持简洁,我使用了字段而不是下面示例中的属性)

public class A : B
{
    public string prop1;
    public int prop2;
}

public class B
{
    public byte propX;
    public float propY;
}

public class C
{
    public byte propX;
    public float propY;
    public string prop1;
    public int prop2;
}

public class Merger
{
    public static object Merge(object copyFrom, object copyTo)
    { 
        //do some work
        //maybe <T> generically refactor?
    }
}

合并类只是一个假的例子,通过泛型来做这个是最优的,但我首先要问的是这样的能力是否已经存在。我可以想象自己使用反射来做这件事,但我只是想先把它扔出来以获得更好的想法。

真实世界上下文:这实际上是一个与MVVM相关的问题,因为我试图使用从EF回来的不同类来填充ViewModel实例。

4 个答案:

答案 0 :(得分:8)

查看AutoMapper之类的工具和库 - 这些工具和库可以轻松处理这样的案例 - 还有更多!无需重新发明轮子 - 只需使用该工具! : - )

您基本上会在A和C类之间定义一个映射,如下所示:

Mapper.CreateMap<A, C>();

然后,您可以让AutoMapper根据该映射从A的实例到C的实例进行映射,如下所示:

C yourC = Mapper.Map<A, C>(instanceOfA);

AutoMapper根据属性名称(和类型)执行默认映射,但您可以通过多种方式扩展和影响它,以包括从一个属性到另一个属性的映射,即使名称(或类型)不匹配100%。这是非常灵活和完善的 - 绝对值得认真看待!

答案 1 :(得分:1)

using System;
using System.Linq;
using System.Reflection;

public class Merger
{
    public static TTarget Merge<TTarget>(object copyFrom) where TTarget : new()
    {
        var flags = BindingFlags.Instance | BindingFlags.Public |
                    BindingFlags.NonPublic;
        var targetDic = typeof(TTarget).GetFields(flags)
                                       .ToDictionary(f => f.Name);
        var ret = new TTarget();
        foreach (var f in copyFrom.GetType().GetFields(flags))
        {
            if (targetDic.ContainsKey(f.Name))
                targetDic[f.Name].SetValue(ret, f.GetValue(copyFrom));
            else
                throw new InvalidOperationException(string.Format(
                    "The field “{0}” has no corresponding field in the type “{1}”.",
                    f.Name, typeof(TTarget).FullName));
        }
        return ret;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var a = new A { prop1 = "one", prop2 = 2, propX = 127, propY = 0.47f };
        var c = Merger.Merge<C>(a);
        Console.WriteLine(c.prop1);  // prints one
        Console.WriteLine(c.prop2);  // prints 2
        Console.WriteLine(c.propX);  // prints 127
        Console.WriteLine(c.propY);  // prints 0.47
    }
}

答案 2 :(得分:0)

到目前为止,这不是最好的解决方案,但基于您提供的对象图,您可以通过XML序列化第一个对象,并将XML反序列化为第二个对象来实现此目的。

您提议的Merger方法可能如下所示:

public class Merger
{
    public static object Merge(object copyFrom, object copyTo)
    { 
        var xmlContent = MyXMLSerializationMethod(copyFrom);
        MyXMLDeserializationMethod(xmlContent, typeof(copyTo), out copyTo);
        return copyTo;
    }
}

答案 3 :(得分:0)

关于使用AutoMapper在MVVM和MVC上下文中解决此问题的好帖子

http://www.bengtbe.com/blog/post/2009/04/14/Using-AutoMapper-to-map-view-models-in-ASPNET-MVC.aspx