C# 你将如何改进这门肤浅的复制课?

C# 你将如何改进这门肤浅的复制课?,c#,reflection,shallow-copy,C#,Reflection,Shallow Copy,我用一个静态方法编写了一个类,该方法将属性值从一个对象复制到另一个对象。它不关心每个对象是什么类型,只关心它们具有相同的属性。它能满足我的需要,所以我不会进一步设计它,但你会做什么改进 代码如下: public class ShallowCopy { public static void Copy<From, To>(From from, To to) where To : class where From : class {

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

代码如下:

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

一个新方法可能有用,该方法创建了
To
的新实例,并在返回之前调用
Copy()
方法

像这样:

public static To Create<From, To>(From from)
    where To : class, new()
    where From : class
{
    var to = new To();
    Copy(from, to);
    return to;
}
要创建的公共静态(从)
到何处:类,新()
来自哪里:班级
{
var to=新到();
抄送(从,到);
返回;
}

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

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

但请注意,我并不真正同意这种一般方法。我更喜欢在每个DTO实现的DTO上复制的强大契约。

如果传递的对象类型共享某些属性,但不共享所有属性,请决定要执行的操作。在尝试设置属性值之前,请检查
To
对象中的
From
对象中是否存在该属性。当你来到一个不存在的地方时,做“正确的事情”。如果所有公共属性都需要相同,则需要检查是否已将
对象上的所有公共属性都设置为
对象,并处理未正确设置的情况

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

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

  • 在泛型类型中执行大部分工作,而不仅仅是在泛型方法中。这允许您缓存属性,并允许类型推断。类型推断对“TFrom”参数很重要,因为它允许使用匿名类型

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


如何将其用于列表或包含多个列表的对象?这将是一个深度副本。基本上与上面相同,但是递归的,您会发现一个
PropertyInfo
和一个
PropertyType
可以从
IEnumerable
继承。显然,您需要处理清除目标可枚举项之类的事情。
MemberInfo[] sm = FormatterServices.GetSerializableMembers(typeof(From));
object[] data = FormatterServices.GetObjectData(from, sm);
FormatterServices.PopulateObjectMembers(to, sm, data);