title: Dynamic object property populator (without reflection)
body: <p>I want to populate an object's properties without using reflection in a manner similar to the <a href="http://www.codeproject.com/KB/database/DynamicMethod_ILGenerator.aspx" rel="nofollow noreferrer">DynamicBuilder on CodeProject</a>. The CodeProject example is tailored for populating entities using a DataReader or DataRecord. I use this in several DALs to good effect. Now I want to modify it to use a dictionary or other data agnostic object so that I can use it in non DAL code --places I currently use reflection. I know almost nothing about OpCodes and IL. I just know that it works well and is faster than reflection.</p>
  
  <p>I have tried to modify the CodeProject example and because of my ignorance with IL, I have gotten stuck on two lines.</p>
  
  <ul>
  <li>One of them deals with dbnulls and I'm pretty sure I can just lose it, but I don't know if the lines preceding and following it are related and which of them will also need to go.</li>
  <li>The other, I think, is the one that pulled the value out of the datarecord before and now needs to pull it out of the dictionary. I think I can replace the "getValueMethod" with my "property.Value" but I'm not sure.</li>
  </ul>
  
  <p>I'm open to alternative/better ways of skinning this cat too.</p>
  
  <p>Here's the code so far (the commented out lines are the ones I'm stuck on):</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Reflection;
  using System.Reflection.Emit;
  
  public class Populator&lt;T&gt;
  {
      private delegate T Load(Dictionary&lt;string, object&gt; properties);
      private Load _handler;
      private Populator() { }
      public T Build(Dictionary&lt;string, object&gt; properties)
      {
          return _handler(properties);
      }
      public static Populator&lt;T&gt; CreateBuilder(Dictionary&lt;string, object&gt; properties)
      {
          //private static readonly MethodInfo getValueMethod = typeof(IDataRecord).GetMethod("get_Item", new [] { typeof(int) });
          //private static readonly MethodInfo isDBNullMethod = typeof(IDataRecord).GetMethod("IsDBNull", new [] { typeof(int) });
          Populator&lt;T&gt; dynamicBuilder = new Populator&lt;T&gt;();
          DynamicMethod method = new DynamicMethod("Create", typeof(T), new[] { typeof(Dictionary&lt;string, object&gt;) }, typeof(T), true);
          ILGenerator generator = method.GetILGenerator();
          LocalBuilder result = generator.DeclareLocal(typeof(T));
          generator.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes));
          generator.Emit(OpCodes.Stloc, result);
          int i = 0;
          foreach (var property in properties)
          {
              PropertyInfo propertyInfo = typeof(T).GetProperty(property.Key, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.FlattenHierarchy | BindingFlags.Default);
              Label endIfLabel = generator.DefineLabel();
  
              if (propertyInfo != null &amp;&amp; propertyInfo.GetSetMethod() != null)
              {
                  generator.Emit(OpCodes.Ldarg_0);
                  generator.Emit(OpCodes.Ldc_I4, i);
                  //generator.Emit(OpCodes.Callvirt, isDBNullMethod);
                  generator.Emit(OpCodes.Brtrue, endIfLabel);
  
                  generator.Emit(OpCodes.Ldloc, result);
                  generator.Emit(OpCodes.Ldarg_0);
                  generator.Emit(OpCodes.Ldc_I4, i);
                  //generator.Emit(OpCodes.Callvirt, getValueMethod);
  
                  generator.Emit(OpCodes.Unbox_Any, property.Value.GetType());
                  generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());
                  generator.MarkLabel(endIfLabel);
              }
              i++;
          }
  
          generator.Emit(OpCodes.Ldloc, result);
          generator.Emit(OpCodes.Ret);
          dynamicBuilder._handler = (Load)method.CreateDelegate(typeof(Load));
          return dynamicBuilder;
      }
  }
  </code></pre>
  
  <p>EDIT:</p>
  
  <p>Using Marc Gravell's PropertyDescriptor implementation (with HyperDescriptor) the code is simplified a hundred-fold. I now have the following test:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using Hyper.ComponentModel;
  
  namespace Test
  {
      class Person
      {
          public int Id { get; set; }
          public string Name { get; set; }
      }
  
      class Program
      {
          static void Main()
          {
              HyperTypeDescriptionProvider.Add(typeof(Person));
              var properties = new Dictionary&lt;string, object&gt; { { "Id", 10 }, { "Name", "Fred Flintstone" } };
              Person person = new Person();
              DynamicUpdate(person, properties);
              Console.WriteLine("Id: {0}; Name: {1}", person.Id, person.Name);
              Console.ReadKey();
          }
  
          public static void DynamicUpdate&lt;T&gt;(T entity, Dictionary&lt;string, object&gt; properties)
          {
              foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(typeof(T)))
                  if (properties.ContainsKey(propertyDescriptor.Name))
                      propertyDescriptor.SetValue(entity, properties[propertyDescriptor.Name]);
          }
      }
  }
  </code></pre>
  
  <p>Any comments on performance considerations for both TypeDescriptor.GetProperties() &amp; PropertyDescriptor.SetValue() are welcome...</p>