复制对象属性:reflection或序列化 – 哪个更快?

我有两个相同类型的对象,需要将属性值从一个对象复制到另一个对象。 有两种选择:

  1. 使用reflection,浏览第一个对象的属性并复制值。

  2. 序列化第一个对象并反序列化副本。

两者都符合我的要求,问题是我在速度(成本)方面更好地使用哪些?

class Person { public int ID { get; set; } public string Firsthand { get; set; } public string LastName { get; set; } public int Age { get; set; } public decimal Weight { get; set; } } 

需要将属性值从Person p1复制到Person p2

对于这个简单的样本 – 哪种方法更快?

更新

对于序列化,我使用此处建议的ObjectCopier: 深度克隆对象

对于reflection,我使用此代码:

 foreach (PropertyInfo sourcePropertyInfo in copyFromObject.GetType().GetProperties()) { PropertyInfo destPropertyInfo = copyToObject.GetType().GetProperty(sourcePropertyInfo.Name); destPropertyInfo.SetValue( copyToObject, sourcePropertyInfo.GetValue(copyFromObject, null), null); } 

这完全取决于您要复制的内容以及您计划使用的串行器类型。 使用序列化器的情况是, 其中一些可能实际上使用reflection作为构建对象的基础机制。

编辑#1:据我所知,你class级使用的BinaryFormatter确实利用reflection来完成它的工作。 所以问题是,你能为你的类型编写比微软更好(更快吗?)的自定义reflection代码?

编辑#2:出于好奇,我进行了简单的测试。 BinaryFormatter vs执行浅拷贝的reflection。 我用过的reflection代码可以在这里看到:

 var newPerson = Activator.CreateInstance(); var fields = newPerson.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance); foreach (var field in fields) { var value = field.GetValue(person); field.SetValue(newPerson, value); } 

与您正在使用的ObjectCopier类相比,结果是什么? reflection似乎比序列化代码快7倍 。 但是,这适用于具有公共字段的 Person类。 对于属性,差异仍然是显着的,但它只是快2倍。

我假设差异来自于BinaryFormatter需要使用流,这会引入额外的开销。 然而,这只是我的假设,可能远非事实。

我在这里可以找到我使用的测试程序的源代码。 欢迎任何人指出它的缺陷和可能的问题:-)


边注
正如所有“我想知道…”基准一样,我建议你带着一点点盐。 只有在其性能实际成为问题时才应进行此类优化。

最终,通用序列化器(例如BinaryFormatter ,通过ObjectCopier正在使用reflection 。 它们如何使用它取决于特定的序列化程序,但如果您进行序列化,则总会产生额外的开销。

由于您只需要浅拷贝,因此像AutoMapper这样的工具是最合适的工具; 再次,它正在使用reflection(但我希望它是“正确的方式”,即不通过GetValue() / SetValue() ),但它没有序列化成本。

在这种情况下,序列化是过度的; AutoMapper非常合理。 如果你想要深度克隆,它会变得更加棘手……序列化可能会开始变得诱人。 我仍然可能不会自己选择BinaryFormatter ,但我对序列化非常挑剔; p

通过GetValue()等对一些基本reflection做同样的事情当然是微不足道的,但这会很慢。 这里另一个有趣的选择是你可以使用Expression API在运行时创建一个对象复制器……但是…… AutoMapper会在这里完成你需要的所有东西,所以它似乎是多余的工作。

二进制序列化非常快我为这类问题使用了很多

深度克隆对象

如果您在运行时复制属性,则reflection就是答案。 如果不是在运行时,我会去序列化。 Serialization vs Reflection看一下这个。

 void Copy(object copyToObject, object copyFromObject) { BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; FieldInfo[] fields = copyFromObject.GetType().GetFields(flags); for (int i = 0; i < fields.Length; ++i) { BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; FieldInfo field = copyFromObject.GetType().GetField(fields[i].Name, bindFlags); FieldInfo toField = copyToObject.GetType().GetField(fields[i].Name, bindFlags); if(field != null) { toField.SetValue(copyToObject, field.GetValue(copyFromObject)); } } }