Sunday, March 25, 2007

Generic copy object using Lightweight Code Generation

I was involved in a discussion on microsoft.public.dotnet.framework.clr regarding reflection and lightweight code generation. The original topic was in regards to a 2x slowdown using reflection in .NET 2.0 over 1.1, which was ultimately recognised as a bug by the Microsoft CLR team. I brought up the possibility of using LCG as an alternative in 2.0, and the one of the contributers presented some good examples of using Delegate.CreateDelegate. Here I wanted to present a use of LCG to copy all the public read/write properties of any object. The meat of the example was the GenerateCopyDelegate function, as follows:
static CopyPublicPropertiesDelegate<T> GenerateCopyDelegate<T>()
{
    Type type = typeof(T);
 
    DynamicMethod dm = new DynamicMethod(type.Name, null, new Type[] { typeof(T), typeof(T) }, typeof(Program).Module);
 
    ILGenerator il = dm.GetILGenerator();
 
    PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
 
    foreach (PropertyInfo prop in props)
    {
        if (prop.CanRead && prop.CanWrite)
        {
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Ldarg_0);
            il.EmitCall(OpCodes.Callvirt, prop.GetGetMethod(), null);
            il.EmitCall(OpCodes.Callvirt, prop.GetSetMethod(), null);
        }
    }
    il.Emit(OpCodes.Ret);
 
    return (CopyPublicPropertiesDelegate<T>)dm.CreateDelegate(typeof(CopyPublicPropertiesDelegate<T>));
}

 

Method Calls (per iteration) Total Calls
Delegate get_* set_*
LCG 1 6 6 13,000,000
Delegate 12 6 6 24,000,000

No comments: