Freigeben über


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!