开发者

Member by Member copy

In an application we have we have a set of ORM objects, and a set of business object. Most of the time we're simply doing a member by member copy. Other times we process the data slightly. For instance:

tEmployee emp = new tEmployee();
emp.Name = obj.Name;
emp.LastN开发者_JS百科ame = obj.LastName;
emp.Age = obj.Age;
emp.LastEdited = obj.LastEdited.ToGMT();

Now this works just fine, and is rather fast, but not exactly terse when it comes to coding. Some of our objects have upto 40 members, so doing a copy like this can get rather tedious. Granted you only need 2 methods for two->from conversion, but I'd like to find a better way to do this.

Reflection is an natural choice, but on a benchmark I found that execution time was about 100x slower when using reflection.

Is there a better way to go about this?

Clarification: I'm converting from one type to another. In the above example obj is of type BLogicEmployee and emp is of type tEmployee. They share member names, but that is it.


You might want to check out AutoMapper.


If you don't mind it being a bit slow the first time you can compile a lambda expression:

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


Reflection can be sped up an awful lot if you use delegates. Basically, you can create a pair of delegates for each getter/setter pair, and then execute those - it's likely to go very fast. Use Delegate.CreateDelegate to create a delegate given a MethodInfo etc. Alternatively, you can use expression trees.

If you're creating a new object, I already have a bunch of code to do this in MiscUtil. (It's in the MiscUtil.Reflection.PropertyCopy class.) That uses reflection for properties to copy into existing objects, but a delegate to convert objects into new ones. Obviously you can adapt it to your needs. I'm sure if I were writing it now I'd be able to avoid the reflection for copying using Delegate.CreateDelegate, but I'm not about to change it :)


Consider using AutoMapper. From its documentation:

.. AutoMapper works best as long as the names of the members match up to the source type's members. If you have a source member called "FirstName", this will automatically be mapped to a destination member with the name "FirstName".

This will save you a great deal of explicit mapping, and AutoMapper of course allows for the customization of particular mappings along the lines of:

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


Object.MemberwiseClone might be useful if all you need is a shallow clone. Not sure how well it performs though, and obviously any complex objects would need additional handling to ensure a proper copy.


See if you can use this

RECAP: and class must be Serializable for this to work.

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


Look att Automapper it can autmatically map your objects if your fields match...

http://automapper.codeplex.com/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜