复制对象属性:反射或序列化 - 哪个更快?

发布于 2024-12-16 11:13:02 字数 1060 浏览 4 评论 0原文

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

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

  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:深度克隆对象

为了反思,我使用以下代码:

foreach (PropertyInfo sourcePropertyInfo in copyFromObject.GetType().GetProperties())  
{
    PropertyInfo destPropertyInfo = copyToObject.GetType().GetProperty(sourcePropertyInfo.Name);

    destPropertyInfo.SetValue(
        copyToObject,
        sourcePropertyInfo.GetValue(copyFromObject, null),
        null);
}

I have two objects of the same type and need to copy property values from one object to another. There are two options:

  1. Use reflection, navigate through the properties of the first object and copy the values.

  2. Serialize the first object and deserialize a copy.

Both work for my requirement, the question is which do I better use in the terms of speed (cost)?

Example

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

Need to copy property values from Person p1 to Person p2.

For this simple sample - which method is faster?

Update

For serialization I use the ObjectCopier suggested here: Deep cloning objects

For reflection I use this code:

foreach (PropertyInfo sourcePropertyInfo in copyFromObject.GetType().GetProperties())  
{
    PropertyInfo destPropertyInfo = copyToObject.GetType().GetProperty(sourcePropertyInfo.Name);

    destPropertyInfo.SetValue(
        copyToObject,
        sourcePropertyInfo.GetValue(copyFromObject, null),
        null);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

森林散布 2024-12-23 11:13:02

这完全取决于您想要复制的内容以及您计划使用哪种序列化程序。序列化器的问题是,其中一些可能实际上使用反射作为构建对象的底层机制。

编辑#1:据我所知,您的类使用的BinaryFormatter确实利用反射来完成其工作。所以问题是,您能否为您的类型编写比 Microsoft 为一般场景编写的更好(更快?)的自定义反射代码?

编辑#2:出于好奇,我运行了简单的测试。 BinaryFormatter 与执行浅复制方面的反射。我使用的反射代码可以在这里看到:

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

与您正在使用的 ObjectCopier 类相比,结果是什么?反射的执行速度似乎比序列化代码快 7 倍。然而,这适用于具有公共字段Person类。对于属性来说,差异仍然很明显,但速度只快了 2 倍。

我认为差异来自于 BinaryFormatter 需要使用流,这会带来额外的开销。但这只是我的假设,可能与事实相去甚远。

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


旁注
与所有“我想知道...”基准一样,我建议您持保留态度。仅当其性能确实成为问题时才应进行此类优化。

It all depends on what you want to copy, and what kind of serializer you plan to use. Thing with serializers is, some of them might be actually using reflection as underlying mechanism of building objects.

Edit #1: As far as I know, BinaryFormatter used by your class does utilize reflection to do its work. So question is, can you write better (faster?) custom reflection code for your types than Microsoft did for general scenario?

Edit #2: Out of curiosity, I've run simple test. BinaryFormatter vs reflection in terms of performing shallow copy. Reflection code I used can be seen here:

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

What are the results compared to ObjectCopier class you're using? Reflection seems to perform 7 times faster than serialization code. This however applies to Person class with public fields. For properties, difference is still noticable, but it's only 2 times faster.

I assume difference comes from the fact that BinaryFormatter needs to use streams, which introduce additional overhead. Yet this is just my assumption, which might be far from facts.

Source code for testing program I used can be found here. Anybody is welcome to point flaws and possible problems with it :-)


Sidenote
As with all "I was wondering..." benchmarks, I suggest you take it with a grain of salt. Such optimizations should be only made when their performance actually becomes an issue.

爱,才寂寞 2024-12-23 11:13:02

最终,通用序列化器(例如通过ObjectCopierBinaryFormatter正在使用反射。他们如何使用它取决于特定的序列化程序,但如果您进行序列化,总是会涉及额外的开销。

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

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

当然,纠正一些通过以下方式执行相同操作的基本反射是微不足道的 : GetValue() 等,但这会很慢。这里另一个有趣的选项是,您可以使用Expression API 在运行时创建对象复制器...但是...AutoMapper 在这里完成了您需要的所有操作,因此这似乎是多余的工作。

Ultimately, general-purpose serializers (such as BinaryFormatter, via ObjectCopier) are using reflection. How well they use it depends on the specific serializer, but there is always extra overhead involved if you are serializing.

Since you only want a shallow copy, a tool like AutoMapper is the most appropriate tool here; again, it is using reflection (but I expect it is doing it "the right way", i.e. not via GetValue()/SetValue()), but it doesn't have the serialization costs.

In this scenario, serialization is overkill; AutoMapper is perfectly reasonable. If you wanted deep-clones, it gets trickier... serialization may start being tempting. I still probably wouldn't choose BinaryFormatter myself, but I'm very fussy about serialization ;p

It would of course be trivial to right some basic reflection that does the same via GetValue() etc, but that would be slow. Another interesting option here is that you can use the Expression API to create an object copier at runtime.... but... AutoMapper does everything you'd need here, so it seems redundant effort.

人心善变 2024-12-23 11:13:02

二进制序列化非常快,我经常使用它来解决此类问题

深度克隆对象

Binary serialization is very fast I use it a lot for this kind of problem

Deep cloning objects

秋千易 2024-12-23 11:13:02

如果您在运行时复制属性,反射就是答案。如果不是在运行时,我会进行序列化。
序列化与反射看一下。

If you are copying the properties during run time, reflection would be the answer. I would go for serialization if its not during run time.
Serialization vs Reflection look at this once.

久光 2024-12-23 11:13:02
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));
        }
    }
}
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));
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文