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

Monday, March 19, 2007

A simple console logger

A very simple class for logging output to the console. What's special about it?
  • Intended for the console only.
    • I wanted to keep the code very simple.
  • Uses colour to differentiate the log message based on type: INFO, WARN or ERROR.
  • Supports immediate or buffered output
    • All colour output is honoured in buffered mode.
    • Use Logger.Flush() to display pending output.
Get it here.

A better FindControl: FindControlOf<T>

Whilst helping a colleague with some ASP.NET questions, I found a number of blocks enumerating the Controls collection for specific control types. Having to enumerate and determine the control type can become quite tedious, so I provided an iterator to simplify:

   1:  static IEnumerable FindControlsOf<T>(Control parent)
   2:      where T : class
   3:  {
   4:      foreach (Control control in parent.Controls)
   5:      {
   6:          T item = control as T;
   7:          if (item != null)
   8:          {
   9:              yield return item;
  10:          }
  11:   
  12:          // Don't enumerate the children, if control is type T as an optimization, since our
  13:          // typical search criteria is not container controls.  If the criteria changes, 
  14:          // remove the "item == null" check.
  15:          if (item == null && control.Controls.Count > 0)
  16:          {
  17:              foreach (T child in FindControlsOf<T>(control))
  18:              {
  19:                  yield return child;
  20:              }
  21:          }
  22:      }
  23:  }


Making it easy to enumerate controls of a specific type:

   1:  foreach (MyControl sa in FindControlsOf<MyControl>(pnlMyContainer))
   2:  {
   3:      ...
   4:  }


I should point out that this code generates recursive state machines depending on the depth of the hierarchy of controls, so it should be used carefully.