사용 Reflection.Emit를가 ExpandoObject을 기입하는 일반적인 방법을 만들 수 있습니다.
또는 표현식을 사용하는 것 (아마 .NET 4에서만 가능할 것입니다).
위의 방법 중 어느 것도 위임을 설정할 때만 리플렉션을 사용하지 않습니다 (캐시해야 함).
여기에 사전을 채우기 위해 Reflection.Emit 코드가 있습니다 (ExpandoObject가 멀지 않은 것 같습니다).
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);
}
반사 성능은 실제로 너무 끔찍하지 않습니다. 이 작업을 수행해야하는 인스턴스가 매우 많은 경우 지정된 익명 형식의 PropertyInfo 항목을 캐시 한 다음 해당 PropertyInfo 항목을 반복하여 각 인스턴스의 속성을 확인할 수 있습니다. 각 속성에 대해 GetMethod에 대한 대리자를 만들고 캐시 할 수도 있습니다. –