你会如何改进这种浅层复制课程?

时间:2021-11-07 03:52:45

I've written a class with a single static method that copies property values from one object to another. It doesn't care what type each object is, only that they have identical properties. It does what I need, so I'm not engineering it further, but what improvements would you make?

我用一个静态方法编写了一个类,它将属性值从一个对象复制到另一个对象。它不关心每个对象是什么类型,只关心它们具有相同的属性。它做了我需要的,所以我不会进一步设计它,但你会做出哪些改进?

Here's the code:

这是代码:

public class ShallowCopy
{
    public static void Copy<From, To>(From from, To to)
        where To : class
        where From : class
    {
        Type toType = to.GetType();
        foreach (var propertyInfo in from.GetType().GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance))
        {
            toType.GetProperty(propertyInfo.Name).SetValue(to, propertyInfo.GetValue(from, null), null);
        }
    }
}

I'm using it as follows:

我正在使用它如下:

EmployeeDTO dto = GetEmployeeDTO();
Employee employee = new Employee();
ShallowCopy.Copy(dto, employee);

4 个解决方案

#1


Are your DTOs serializable? I would expect so, in which case:

您的DTO是否可序列化?我希望如此,在这种情况下:

MemberInfo[] sm = FormatterServices.GetSerializableMembers(typeof(From));
object[] data = FormatterServices.GetObjectData(from, sm);
FormatterServices.PopulateObjectMembers(to, sm, data);

But note that I don't really agree with this general approach. I would prefer a strong contract for copying on your DTOs that each DTO implements.

但请注意,我并不同意这种一般方法。我希望有一份强有力的合同来复制每个DTO实施的DTO。

#2


  • Change your type parameter names to comply with naming conventions, e.g. TFrom and TTo, or TSource and TDest (or TDestination).

    更改您的类型参数名称以符合命名约定,例如TFrom和TTo,或TSource和TDest(或TDestination)。

  • Do most of your work in a generic type instead of in just a generic method. That allows you to cache the properties, as well as allowing type inference. Type inference is important on the "TFrom" parameter, as it will allow anonymous types to be used.

    您的大部分工作都是通用类型而不是通用方法。这允许您缓存属性,以及允许类型推断。类型推断对“TFrom”参数很重要,因为它允许使用匿名类型。

  • You could potentially make it blindingly fast by dynamically generating code to do the property copying and keeping it in a delegate which is valid for the "from" type. Or potentially generate it for every from/to pair, which would mean the actual copying wouldn't need to use reflection at all! (Preparing the code would be a one-time hit per pair of types, but hopefully you wouldn't have too many pairs.)

    通过动态生成代码来执行属性复制并将其保存在对“from”类型有效的委托中,您可能会使它快速地变得快速。或者可能为每个from / to对生成它,这意味着实际复制根本不需要使用反射! (准备代码将是每对类型的一次性命中,但希望你不会有太多对。)

#3


A new method that created a new instance of To and called the Copy() method before returning might be useful.

在返回之前创建To的新实例并调用Copy()方法的新方法可能很有用。

Like this:

public static To Create<From, To>(From from)
    where To : class, new()
    where From : class
{
    var to = new To();
    Copy(from, to);
    return to;
}

#4


Decide what you want to do if passed objects of types that share some properties but not all. Check for the existence of the property in the From object in the To object before trying to set it's value. Do the "right thing" when you come to a property that doesn't exist. If all of the public properties need to be identical, then you will need to check if you've set all of them on the To object and handle the case where you haven't appropriately.

如果传递的是共享某些属性但不是全部属性的对象,请确定要执行的操作。在尝试设置其值之前,检查To对象中From对象中是否存在属性。当你来到一个不存在的财产时,做“正确的事”。如果所有公共属性都需要相同,那么您需要检查是否已将所有这些属性设置为To对象并处理您没有适当的情况。

I'd also suggest that you may want to use attributes to decorate the properties that need to be copied and ignore others. This would allow you to go back and forth between the two different objects more easily and continue to maintain some public properties that are derived rather than stored on your business object.

我还建议您可能希望使用属性来装饰需要复制的属性并忽略其他属性。这将允许您更轻松地在两个不同对象之间来回切换,并继续维护派生的一些公共属性,而不是存储在业务对象上。

#1


Are your DTOs serializable? I would expect so, in which case:

您的DTO是否可序列化?我希望如此,在这种情况下:

MemberInfo[] sm = FormatterServices.GetSerializableMembers(typeof(From));
object[] data = FormatterServices.GetObjectData(from, sm);
FormatterServices.PopulateObjectMembers(to, sm, data);

But note that I don't really agree with this general approach. I would prefer a strong contract for copying on your DTOs that each DTO implements.

但请注意,我并不同意这种一般方法。我希望有一份强有力的合同来复制每个DTO实施的DTO。

#2


  • Change your type parameter names to comply with naming conventions, e.g. TFrom and TTo, or TSource and TDest (or TDestination).

    更改您的类型参数名称以符合命名约定,例如TFrom和TTo,或TSource和TDest(或TDestination)。

  • Do most of your work in a generic type instead of in just a generic method. That allows you to cache the properties, as well as allowing type inference. Type inference is important on the "TFrom" parameter, as it will allow anonymous types to be used.

    您的大部分工作都是通用类型而不是通用方法。这允许您缓存属性,以及允许类型推断。类型推断对“TFrom”参数很重要,因为它允许使用匿名类型。

  • You could potentially make it blindingly fast by dynamically generating code to do the property copying and keeping it in a delegate which is valid for the "from" type. Or potentially generate it for every from/to pair, which would mean the actual copying wouldn't need to use reflection at all! (Preparing the code would be a one-time hit per pair of types, but hopefully you wouldn't have too many pairs.)

    通过动态生成代码来执行属性复制并将其保存在对“from”类型有效的委托中,您可能会使它快速地变得快速。或者可能为每个from / to对生成它,这意味着实际复制根本不需要使用反射! (准备代码将是每对类型的一次性命中,但希望你不会有太多对。)

#3


A new method that created a new instance of To and called the Copy() method before returning might be useful.

在返回之前创建To的新实例并调用Copy()方法的新方法可能很有用。

Like this:

public static To Create<From, To>(From from)
    where To : class, new()
    where From : class
{
    var to = new To();
    Copy(from, to);
    return to;
}

#4


Decide what you want to do if passed objects of types that share some properties but not all. Check for the existence of the property in the From object in the To object before trying to set it's value. Do the "right thing" when you come to a property that doesn't exist. If all of the public properties need to be identical, then you will need to check if you've set all of them on the To object and handle the case where you haven't appropriately.

如果传递的是共享某些属性但不是全部属性的对象,请确定要执行的操作。在尝试设置其值之前,检查To对象中From对象中是否存在属性。当你来到一个不存在的财产时,做“正确的事”。如果所有公共属性都需要相同,那么您需要检查是否已将所有这些属性设置为To对象并处理您没有适当的情况。

I'd also suggest that you may want to use attributes to decorate the properties that need to be copied and ignore others. This would allow you to go back and forth between the two different objects more easily and continue to maintain some public properties that are derived rather than stored on your business object.

我还建议您可能希望使用属性来装饰需要复制的属性并忽略其他属性。这将允许您更轻松地在两个不同对象之间来回切换,并继续维护派生的一些公共属性,而不是存储在业务对象上。