Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Member by Member copy

Tags:

c#

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.LastName = 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.

like image 669
Timothy Baldridge Avatar asked Jan 26 '11 20:01

Timothy Baldridge


3 Answers

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);
    }
}
like image 30
ChaosPandion Avatar answered Sep 24 '22 08:09

ChaosPandion


You might want to check out AutoMapper.

like image 145
Ahmad Mageed Avatar answered Sep 24 '22 08:09

Ahmad Mageed


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 :)

like image 31
Jon Skeet Avatar answered Sep 24 '22 08:09

Jon Skeet