For example, if I have two objects, one which is of type Monkey and the other of type Dog, and they both implement IAnimal, which is something like this:
interface IAnimal
{
int numberOfEyes {get; set;}
string name {get; set;}
}
I want to do something like this:
Monkey monkey = new Monkey() { numberOfEyes = 7, name = "Henry" };
Dog dog = new Dog();
MyFancyClass.DynamicCopy(monkey, dog, typeof(IAnimal));
Debug.Assert(dog.numberOfEyes == monkey.numberOfEyes);
I imagine one can create a class like MyFancyClass using reflection... any clever person have an idea?
Thanks, Stephen
Just to throw it in the mix... you can also use AutoMapper to map/copy one object to another.... they don't even have to implement the same interface. To make it work automagically, just the names of the properties have to match and then you just do something like:
Mapper.Map<IAnimal, MyClass>(myInstance);
A reflection based solution follows. Note that the reflection work is done only once per Type and then cached, so the overhead should be minimal. Will work with .NET 3.5 and it is not restricted to interfaces.
Note that I use reflection to get all the properties on type T and filter to the properties that have both getters and setters. I then build an expression tree for each property that retrieves the value from the source and assigns that value to the target. The expression trees are compiled and cached in a static field. When the CopyProperties method is called, it invokes the copier for each property, copying all the properties defined in type T.
// Usage
Monkey monkey = new Monkey() { numberOfEyes = 7, name = "Henry" };
Dog dog = new Dog();
DynamicCopy.CopyProperties<IAnimal>(monkey, dog);
Debug.Assert(dog.numberOfEyes == monkey.numberOfEyes);
...
// The copier
public static class DynamicCopy
{
public static void CopyProperties<T>(T source, T target)
{
Helper<T>.CopyProperties(source, target);
}
private static class Helper<T>
{
private static readonly Action<T, T>[] _copyProps = Prepare();
private static Action<T, T>[] Prepare()
{
Type type = typeof(T);
ParameterExpression source = Expression.Parameter(type, "source");
ParameterExpression target = Expression.Parameter(type, "target");
var copyProps = from prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
where prop.CanRead && prop.CanWrite
let getExpr = Expression.Property(source, prop)
let setExpr = Expression.Call(target, prop.GetSetMethod(true), getExpr)
select Expression.Lambda<Action<T, T>>(setExpr, source, target).Compile();
return copyProps.ToArray();
}
public static void CopyProperties(T source, T target)
{
foreach (Action<T, T> copyProp in _copyProps)
copyProp(source, target);
}
}
}
Copy constructor is what I usually do:
class Monkey : IAnimal
{
public Monkey(IAnimal other)
{
//Copy properties here...
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With