Use Reflection.Emit to create a generic method to populate ExpandoObject.
OR use expressions (perhaps this is only possible in .NET 4).
None of these approaches use reflection when invoked only when setting up a delegate (which obviously needs to be cached).
Here is the Reflection.Emit code to populate the dictionary (I think ExpandoObject is just around the corner);
static T CreateDelegate<T>(this DynamicMethod dm) where T : class { return dm.CreateDelegate(typeof(T)) as T; } static Dictionary<Type, Func<object, Dictionary<string, object>>> cache = new Dictionary<Type, Func<object, Dictionary<string, object>>>(); static Dictionary<string, object> GetProperties(object o) { var t = o.GetType(); Func<object, Dictionary<string, object>> getter; if (!cache.TryGetValue(t, out getter)) { var rettype = typeof(Dictionary<string, object>); var dm = new DynamicMethod(t.Name + ":GetProperties", rettype, new Type[] { typeof(object) }, t); var ilgen = dm.GetILGenerator(); var instance = ilgen.DeclareLocal(t); var dict = ilgen.DeclareLocal(rettype); ilgen.Emit(OpCodes.Ldarg_0); ilgen.Emit(OpCodes.Castclass, t); ilgen.Emit(OpCodes.Stloc, instance); ilgen.Emit(OpCodes.Newobj, rettype.GetConstructor(Type.EmptyTypes)); ilgen.Emit(OpCodes.Stloc, dict); var add = rettype.GetMethod("Add"); foreach (var prop in t.GetProperties( BindingFlags.Instance | BindingFlags.Public)) { ilgen.Emit(OpCodes.Ldloc, dict); ilgen.Emit(OpCodes.Ldstr, prop.Name); ilgen.Emit(OpCodes.Ldloc, instance); ilgen.Emit(OpCodes.Ldfld, prop); ilgen.Emit(OpCodes.Castclass, typeof(object)); ilgen.Emit(OpCodes.Callvirt, add); } ilgen.Emit(OpCodes.Ldloc, dict); ilgen.Emit(OpCodes.Ret); cache[t] = getter = dm.CreateDelegate<Func<object, Dictionary<string, object>>>(); } return getter(o); }
leppie Apr 7 '10 at 17:26 2010-04-07 17:26
source share