如果两个对象具有相同的属性,那么一个值是否可以自动分配?

时间:2013-12-05 20:41:08

标签: c#

这是一个学术问题比什么都重要......我知道有更多实用的方法可以让发展明智......

假设您有以下代码:

  

public MyObject1 AssignTest(MyObject1 obj1,MyObject2 obj2)           {

    }

MyObject1和MyObject2具有完全相同的属性。是否可以自动将MyObject1中指定的所有值分配给MyObject2?而不是以声明方式进行并分配值(即MyObject1.Property1 = MyObject2.Property1等)

7 个答案:

答案 0 :(得分:6)

ValueInjectorAutoMapper等映射库对这种功能非常有帮助。

使用AutoMapper,您可以使用类似

的内容创建映射
Mapper.CreateMap<MyObject1,MyObject2>();

它有许多默认约定,其中一个默认约定会复制具有相同类型/名称的属性。

然后实际做这样的映射

var myObject2 = Mapper.Map<MyObject1,MyObject2>(myObject1);

当然,你也可以通过反射轻松完成这项工作,但是对于像这样的库,有人已经考虑添加各种方便的映射功能,以及完成性能调整。例如,AutoMapper使用IL生成来读取值而不是反射,因此重复映射事物的速度要快得多(非常适合映射大量事物)

答案 1 :(得分:5)

实现这一目标的一种可能性(例如,为了创建自己的自动化程序或理解它基本上如何工作)将是使用(如已建议的)Reflection。代码可能如下所示:

// TODO: error handling
// Test classes
public class A
{
    public string Name { get; set; }
    public int Count;
}

public class B
{
    public string Name { get; set; }
    public int Count;
}
// copy routine
public B CopyAToB(A a)
{
    B b = new B();
    // copy fields
    var typeOfA = a.GetType();
    var typeOfB = b.GetType();
    foreach (var fieldOfA in typeOfA.GetFields())
    {
        var fieldOfB = typeOfB.GetField(fieldOfA.Name);
        fieldOfB.SetValue(b, fieldOfA.GetValue(a));
    }
    // copy properties
    foreach (var propertyOfA in typeOfA.GetProperties())
    {
        var propertyOfB = typeOfB.GetProperty(propertyOfA.Name);
        propertyOfB.SetValue(b, propertyOfA.GetValue(a));
    }

    return b;
}

该功能可以这样使用:

var a = new A
{
    Name = "a",
    Count = 1
};

var b = CopyAToB(a);
Console.Out.WriteLine(string.Format("{0} - {1}", b.Name, b.Count));

输出结果为:

a - 1

请注意,反射的使用需要付出代价 - 它会降低性能。使用反射,您可以访问私有和公共对象成员。例如,这可以从Visual Studio中使用,以创建测试访问器对象,以便访问所有测试对象成员。

请查看现有的自动化程序(请参阅链接的其他答案)并使用它们而不是重新发明轮 - 现有库已针对速度进行了优化,经过全面测试并且非常使用舒适。这样您就可以最大限度地减少代码中的错误。

答案 2 :(得分:1)

有很多工具可以做到这一点。以服务堆栈中的“TranslateTo”例程为例。他们有出色的自动映射(https://github.com/ServiceStack/ServiceStack/wiki/Auto-mapping)。

使用此功能,您只需要:

 obj2 = obj1.TranslateTo<MyObject2>();

简单而优雅!

如果您对其他一些类似主题的引用感兴趣:

答案 3 :(得分:1)

从@pasty的accepted answer开始,我为此创建了通用方法。

public static TDest MapSourceToDest<TSource, TDest>(TSource source)
                                    where TSource : class//We are not creating an instance of source, no need to restrict parameterless constructor
                                    where TDest : class, new()//We are creating an instance of destination, parameterless constructor is needed
{
    if(source == null)
        return null;

    TDest destination = new TDest();

    var typeOfSource = source.GetType();
    var typeOfDestination = destination.GetType();

    foreach(var fieldOfSource in typeOfSource.GetFields())
    {
        var fieldOfDestination = typeOfDestination.GetField(fieldOfSource.Name);
        if(fieldOfDestination != null)
        {
            try
            { fieldOfDestination.SetValue(destination, fieldOfSource.GetValue(source)); }
            catch(ArgumentException) { }//If datatype is mismatch, skip the mapping
        }
    }

    foreach(var propertyOfSource in typeOfSource.GetProperties())
    {
        var propertyOfDestination = typeOfDestination.GetProperty(propertyOfSource.Name);
        if(propertyOfDestination != null)
        {
            try
            { propertyOfDestination.SetValue(destination, propertyOfSource.GetValue(source)); }
            catch(ArgumentException) { }//If datatype is mismatch, skip the mapping
        }
    }

    return destination;
}

可能需要更改通用类型的过滤器;但是其他所有类型都可以跨任何类型工作。为fieldOfDestinationpropertyOfDestination添加空检查,以防万一成员丢失;这增加了一点灵活性。

答案 4 :(得分:0)

AutoMapper是另一个很好用的工具http://automapper.codeplex.com/

您可以使用以下内容从一个对象映射到另一个对象:

Mapper.CreateMap<MyClass, MyDTO>();
var myDTO = Mapper.Map<MyClass, MyDTO>(myClass);

答案 5 :(得分:0)

我改进并概括了@keenthinker 的响应,它始终适用于任何类型的对象。

调用静态方法并传递地图类和对象

var result = SimpleMapper.Map<FromModel, ToModel>(data);

实现:

public static class SimpleMapper
{
    public static T Map<F, T>(F from)
    {
        // inicialize return object
        T b = (T)Activator.CreateInstance(typeof(T));

        // copy fields
        Type typeOfA = typeof(F);
        Type typeOfB = typeof(T);
        foreach (var fieldOfA in typeOfA.GetFields())
        {
            var fieldOfB = typeOfB.GetField(fieldOfA.Name);
            fieldOfB.SetValue(b, fieldOfA.GetValue(from));
        }
        // copy properties
        foreach (var propertyOfA in typeOfA.GetProperties())
        {
            var propertyOfB = typeOfB.GetProperty(propertyOfA.Name);
            propertyOfB.SetValue(b, propertyOfA.GetValue(from));
        }

        return (T)b;
    }
}

答案 6 :(得分:0)

这个问题很老了,但使用 JsonConvert 会更快吗?

MyObject2 obj2 = JsonConvert.DeserializeObject<MyObject2>(JsonConvert.SerializeObject(obj1));