2011-01-26 31 views
5

En una aplicación tenemos un conjunto de objetos ORM y un conjunto de objetos comerciales. La mayoría de las veces simplemente hacemos un miembro por copia de miembro. Otras veces procesamos los datos levemente. Por ejemplo:Miembro por copia del miembro

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

Ahora bien, esto funciona muy bien, y es bastante rápido, pero no exactamente conciso cuando se trata de la codificación. Algunos de nuestros objetos tienen hasta 40 miembros, por lo que hacer una copia como esta puede ser bastante tedioso. De acuerdo, solo necesitas 2 métodos para dos-> conversiones, pero me gustaría encontrar una forma mejor de hacerlo.

La reflexión es una elección natural, pero en un punto de referencia encontré que el tiempo de ejecución era aproximadamente 100 veces más lento cuando se utilizaba la reflexión.

¿Hay una mejor manera de hacerlo?

aclaración: Estoy convirtiendo de un tipo a otro. En el ejemplo anterior, obj es del tipo BLogicEmployee y emp es del tipo tEmployee. Comparten nombres de miembros, pero eso es todo.

Respuesta

5

Es posible que desee comprobar AutoMapper.

+0

+1: He usado Automapper en aplicaciones de producción exactamente para el propósito descrito por el OP, y es * awesome *. – Juliet

1

Object.MemberwiseClone puede ser útil si todo lo que necesita es un clon superficial. Sin embargo, no estoy seguro de lo bien que funciona, y obviamente cualquier objeto complejo necesitaría un manejo adicional para asegurar una copia adecuada.

2

La reflexión puede acelerarse muchísimo si usa delegados. Básicamente, puede crear un par de delegados para cada par getter/setter, y luego ejecutarlos; es probable que sea muy muy rápido. Use Delegate.CreateDelegate para crear un delegado dado un MethodInfo etc. Alternativamente, puede usar árboles de expresiones.

Si está creando un objeto nuevo, ya tengo un montón de código para hacer esto en MiscUtil. (Está en la clase MiscUtil.Reflection.PropertyCopy). Utiliza la reflexión de las propiedades para copiar en objetos existentes, pero un delegado para convertir objetos en objetos nuevos. Obviamente puedes adaptarlo a tus necesidades. Estoy seguro que si estuviera escribiendo ahora me gustaría ser capaz de evitar el reflejo para copiar utilizando Delegate.CreateDelegate, pero no estoy a punto de cambiarlo :)

0

ver si se puede utilizar this

CRÓNICA : y la clase debe ser Serializable para que esto funcione.

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

No desea crear una copia del mismo tipo; desea copiar un conjunto de miembros del tipo A al tipo B, donde ambos tienen miembros muy similares. –

2

Considere el uso de AutoMapper. Desde su documentación:

.. AutoMapper funciona mejor, siempre y cuando los nombres de los miembros coinciden hasta miembros del tipo de fuente. Si usted tiene un miembro de fuente llamada "Nombre", esto automáticamente será asignado a un miembro de destino con el nombre "Nombre".

Esto le ahorrará una gran cantidad de asignación explícita, y AutoMapper por supuesto permite la personalización de las asignaciones particulares a lo largo de las líneas de:

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

Si no te importa que sea un poco lento la primera vez que se puede compilar una expresión 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); 
    } 
} 
Cuestiones relacionadas