blambert/codesnip – Better copy public properties between two objects implementing the same interface, CACHED.
You have some interface, IFoo.
It is implemented by two concrete classes:
- Foo : IFoo (what you expose to the outside world)
- FooEntity : IFoo (what you store someplace; it’s a superset of Foo, which implements, IFoo)
And you want a simple way to copy the IFoo properties from one IFoo object, to another IFoo object, bidirectionally. And IFoo inherits from IBar!
Here it is:
/// <summary>
/// CopyInterfaceProperties cached type properties.
/// </summary>
[ThreadStatic]
private static Dictionary<Type, PropertyInfo[]> copyInterfacePropertiesCache = new Dictionary<Type, PropertyInfo[]>();
/// <summary>
/// Copies all the public instance properties from the source object to the destination object, for the specified type.
/// </summary>
/// <typeparam name="T">The type of the operation.</typeparam>
/// <param name="source">The source object.</param>
/// <param name="destination">The destination object.</param>
public static void CopyInterfaceProperties<T>(T source, T destination)
{
// Get the type. It must be an interface.
Type type = typeof(T);
if (!type.IsInterface)
{
throw new ArgumentException("Is not an interface.", "T");
}
// See if we have the public properties of the type cached. If not, get them and cache them.
PropertyInfo[] properties;
copyInterfacePropertiesCache.TryGetValue(type, out properties);
if (properties == null)
{
properties = GetInterfaceProperties(type);
copyInterfacePropertiesCache.Add(type, properties);
}
// Copy the properties.
foreach (PropertyInfo propertyInfo in properties)
{
propertyInfo.GetSetMethod().Invoke(destination, new object[] { propertyInfo.GetGetMethod().Invoke(source, null) });
}
}
/// <summary>
/// Recursively returns all the properties of the specified type, which must be an interface.
/// </summary>
/// <param name="type">The type of the interface.</param>
/// <returns>An array of PropertyInfo objects representing all the properties of the specified type</returns>
private static PropertyInfo[] GetInterfaceProperties(Type type)
{
// Prameter type must be an interface.
if (!type.IsInterface)
{
throw new ArgumentException("Is not an interface.", "T");
}
// Recursively get properties. Used an array here, fast enough, and keeps the call site simple.
PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (Type baseType in type.GetInterfaces())
{
ArrayAppender<PropertyInfo>(ref properties, GetInterfaceProperties(baseType));
}
// Done.
return properties;
}
/// <summary>
/// Appends new items to an array.
/// </summary>
/// <typeparam name="T">The type of the array.</typeparam>
/// <param name="array">The array being appended to.</param>
/// <param name="newItems">The new items to append to the array being appended to.</param>
private static void ArrayAppender<T>(ref T[] array, T[] newItems)
{
Array.Resize<T>(ref array, array.Length + newItems.Length);
Array.Copy(newItems, 0, array, array.Length - newItems.Length, newItems.Length);
}
Where T is an interface (in this case, IFoo) that both objects implement.
Here’s an example:
Reflection.CopyPublicInstanceProperties<IFoo>(foo, fooEntity);
Best!
Brian
Comments
- Anonymous
February 26, 2009
PingBack from http://www.clickandsolve.com/?p=15537 - Anonymous
February 26, 2009
Why cache the propertyinfo instead of using DynamicMethod? - Anonymous
February 27, 2009
I'm not a real hipster to DynamicMethod, so I will read up on it, and think your suggestion over. Thanks!