2012-01-02 97 views
22

我有一个具有各种属性的对象模型MyObject。有一点,我有这些MyObject的两个实例:实例A和实例B.我想复制和替换实例A中的属性与实例B的属性,如果实例B具有非空值。在C中合并两个对象#

如果我只有1个类有3个属性,没问题,我可以很容易地对它进行硬编码(这是我开始做的)。但我实际上有12个不同的对象模型,每个模型都有10个属性。

这样做的好方法是什么?

+4

你有没有尝试过像AutoMapper(http://automapper.codeplex.com/)? – 2012-01-02 15:37:36

+3

明显的选择是反思,但你会支付表现的惩罚... – jondavidjohn 2012-01-02 15:37:58

+2

看看这个答案;我认为它涵盖了你的情况: http://stackoverflow.com/questions/571982/iterating-over-class-properties – StilesCrisis 2012-01-02 15:38:27

回答

30

更新 改为使用AutoMapper而不是如果您需要调用此方法很多。 Automapper使用Reflection.Emit构建动态方法,并且比反射快得多。'

您可以复制使用反射属性的值:

public void CopyValues<T>(T target, T source) 
{ 
    Type t = typeof(T); 

    var properties = t.GetProperties().Where(prop => prop.CanRead && prop.CanWrite); 

    foreach (var prop in properties) 
    { 
     var value = prop.GetValue(source, null); 
     if (value != null) 
      prop.SetValue(target, value, null); 
    } 
} 

我将它一般以确保类型安全。如果你想包含私有属性,你应该使用覆盖Type.GetProperties(),指定绑定标志。

+0

好吧,这看起来就是我所需要的。使用反射会有性能损失吗? – frenchie 2012-01-02 15:44:16

+1

他的要求只复制非空属性呢? – 2012-01-02 15:45:10

+0

是的,表现的惩罚是相当显着的,根据这家伙慢15倍左右:http://www.manuelabadia.com/blog/PermaLink,guid,772c7152-b00e-4334-b677-bfbdcd8e6b5d.aspx – Bas 2012-01-02 15:46:14

1

您可以使用反射来做到这一点,但正如有人所说,它会有性能损失。

public static class MyClassExtensions 
{ 
    public static void Merge(this MyClass instanceA, MyClass instanceB) 
    { 
     if(instanceA != null && instanceB != null) 
     { 
      if(instanceB.Prop1 != null) 
      { 
       instanceA.Prop1 = instanceB.Prop1; 
      } 


      if(instanceB.PropN != null) 
      { 
       instanceA.PropN = instanceB.PropN; 
      } 
    } 
} 

后来,在某处代码:

someInstanceOfMyClass.Merge(someOtherInstanceOfMyClass); 

既然你与预期一流的设计工作,您可以通过使用扩展方法,像这样达到同样的目的

在一天结束时,您已经将此操作集中在一个扩展方法中,并且如果您添加或删除了类的某个属性,则只需修改扩展方法的实现,即可完成所有操作。

+0

这仍然会导致可维护性问题,因为OP提到 – Bas 2012-01-02 15:49:50

+0

@BasB我不确定这一点,因为正如我在答复中所写的那样,这是一个可预测的设计,我怀疑这个班会加班或删除大量属性。所以,如我所说,在一天结束时,它具有与反思一样的效果,而不会影响性能。 – 2012-01-02 15:52:37

+1

@BasB另外,这些可维护性问题可以在Visual Studio中使用T4模板来解决,因此删除或添加属性可以触发代码生成过程并重新创建此扩展方法。为什么不? WCF和许多.NET框架正在使用代码生成来解决此问题:) – 2012-01-02 15:54:30

6

我试过Merge Two Objects into an Anonymous Type由凯尔芬利,它是完美的工作。

随着TypeMerger合并很简单,只要

var obj1 = new {foo = "foo"}; 

var obj2 = new {bar = "bar"}; 

var mergedObject = TypeMerger.MergeTypes(obj1 , obj2); 

就是这样,你得到的合并对象,除此之外,还有一项规定过于忽略特定属性。您也可以为MVC3使用相同的功能。

+0

好的,谢谢你的回答 – frenchie 2012-04-21 17:45:19

+1

注意:链接不再可用。 – stephenbayer 2014-03-19 22:04:50

+1

@stephenbayer链接现在备份.. – 2014-06-27 13:14:55

0

这是一样的@Bas答案,但对于合并2对象列出

public class Copycontents 
{ 
    public static void Work<T>(IList<T> targetList, IList<T> sourceList, Func<T, int> selector) 
    { 
     var matchingPrimaryKey = targetList.Select(x => selector(x)).ToList(); 

     foreach (var thismatchingPrimaryKey in matchingPrimaryKey) 
     { 
      CopyValues<T>(targetList.Single(x => selector(x) == thismatchingPrimaryKey), 
       sourceList.Single(x => selector(x) == thismatchingPrimaryKey)); 
     } 
    } 

    private static void CopyValues<T>(T target, T source) 
    { 
     Type t = typeof(T); 

     var properties = t.GetProperties().Where(prop => prop.CanRead && prop.CanWrite); 

     foreach (var prop in properties) 
     { 
      var value = prop.GetValue(source, null); 
      if (value != null) 
       prop.SetValue(target, value, null); 
     } 
    } 
} 
0

我写我自己的类用于此目的:ObjectMerger

基本上它使用反射(因此可能会很慢)。它还包含更多功能,例如解析循环引用的对象并合并它们。我的ObjectMerger还包含处理更复杂类的机制,如DelegateMemberInfo。这些将被完全复制,类中的其他对象将被递归合并。

语法如下:

var initialInstance = new MyObjectBase(); // Initialize first object 
var properInstance = new MyObjectWithAlgorithms(); // Initialize second object 
var result = ObjectMerger.MergeObjects(properInstance, initialInstance); // Merge Objects into type of "properInstance" 

我很抱歉地说,这不是原样使用,因为一些外部库在此刻的仓库丢失是由于我公司的限制,但他们可以很容易地被重写。我希望将来可以添加它们。