Timothy Baldridge
Timothy Baldridge

Reputation: 10683

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

Upvotes: 6

Views: 3086

Answers (7)

ChaosPandion
ChaosPandion

Reputation: 78282

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

Upvotes: 3

Tor Andersson
Tor Andersson

Reputation: 109

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

http://automapper.codeplex.com/

Upvotes: 0

ladenedge
ladenedge

Reputation: 13429

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

Upvotes: 2

Ahmad Mageed
Ahmad Mageed

Reputation: 96507

You might want to check out AutoMapper.

Upvotes: 5

VoodooChild
VoodooChild

Reputation: 9784

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

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1502236

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

Upvotes: 2

MikeP
MikeP

Reputation: 7959

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.

Upvotes: 1

Related Questions