会员副本会员

时间:2011-01-26 20:38:55

标签: c#

在一个应用程序中,我们有一组ORM对象和一组业务对象。大多数时候我们只是通过会员副本来做会员。其他时候我们稍微处理数据。例如:

tEmployee emp = new tEmployee();
emp.Name = obj.Name;
emp.LastName = obj.LastName;
emp.Age = obj.Age;
emp.LastEdited = obj.LastEdited.ToGMT();

现在这个工作得很好,并且速度很快,但在编码时并不完全简洁。我们的一些对象有多达40个成员,所以做这样的副本可能会变得相当繁琐。当然,你只需要两种方法来进行双转换,但我想找到一种更好的方法来做到这一点。

反射是一种自然的选择,但在基准测试中,我发现使用反射时执行时间大约慢了100倍。

有没有更好的方法来解决这个问题?

澄清: 我正在从一种类型转换为另一种类型。在上面的例子中,obj的类型为BLogicEmployee,emp的类型为tEmployee。他们共享成员名称,但就是这样。

7 个答案:

答案 0 :(得分:5)

您可能需要查看AutoMapper

答案 1 :(得分:3)

如果你不介意第一次编译lambda表达式时它有点慢:

public static class Copier<T>
{
    private static readonly Action<T, T> _copier;

    static Copier()
    {
        var x = Expression.Parameter(typeof(T), "x");
        var y = Expression.Parameter(typeof(T), "y");
        var expressions = new List<Expression>();
        foreach (var property in typeof(T).GetProperties())
        {
            if (property.CanWrite)
            {
                var xProp = Expression.Property(x, property);
                var yProp = Expression.Property(y, property);
                expressions.Add(Expression.Assign(yProp, xProp));
            }
        }
        var block = Expression.Block(expressions);
        var lambda = Expression.Lambda<Action<T, T>>(block, x, y);
        _copier = lambda.Compile();
    }

    public static void CopyTo(T from, T to)
    {
        _copier(from, to);
    }
}

答案 2 :(得分:2)

如果你使用代表,反思可以加速很多。基本上,您可以为每个getter / setter对创建一对委托,然后执行这些委托 - 它很可能非常。使用Delegate.CreateDelegate创建一个给定MethodInfo等的委托。或者,您可以使用表达式树。

如果你正在创建一个 new 对象,我已经有了一堆代码在MiscUtil中执行此操作。 (它位于MiscUtil.Reflection.PropertyCopy类中。)它使用反射将属性复制到现有对象中,但使用委托将对象转换为新对象。显然,你可以根据自己的需要进行调整。我敢肯定,如果我现在正在写它,我可以避免使用Delegate.CreateDelegate进行复制的反射,但我不打算改变它:)

答案 3 :(得分:2)

考虑使用AutoMapper。从其文档:

  

..只要AutoMapper效果最好   成员的名字最多匹配   源类型的成员。如果你有   一个名为“FirstName”的源成员,   这将自动映射到a   目的地成员的名字   “姓”。

这将为您节省大量的显式映射,AutoMapper当然允许自定义特定的映射:

 Mapper.CreateMap<Model.User, Api.UserInfo>()
       .ForMember(s => s.Address, opt => opt.Ignore())
       .ForMember(s => s.Uri, opt => opt.MapFrom(c => HttpEndpoint.GetURI(c)))

答案 4 :(得分:1)

如果您需要的只是浅层克隆,那么

Object.MemberwiseClone可能会有用。不确定它的性能如何,显然任何复杂的对象都需要额外的处理来确保正确的复制。

答案 5 :(得分:0)

看看您是否可以使用this

回顾: 和class必须是Serializable才能工作。

public static T DeepClone<T>(T obj)
{
 using (var ms = new MemoryStream())
 {
   var formatter = new BinaryFormatter();
   formatter.Serialize(ms, obj);
   ms.Position = 0;

   return (T) formatter.Deserialize(ms);
 }
}

答案 6 :(得分:0)

看看自动映射器,如果你的字段匹配,它可以自动映射你的对象......

http://automapper.codeplex.com/