Reputation: 10683
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
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
Reputation: 109
Look att Automapper it can autmatically map your objects if your fields match...
http://automapper.codeplex.com/
Upvotes: 0
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
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
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
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