Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
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!