Я знаю, что это можно сделать, загрузив MethodInfo
, затем получив ParameterInfo
, а затем получив атрибут этого ParameterInfo
в IL; Я просто стараюсь не писать столько IL.
Да, в значительной степени, в IL; IL мощен, но не особенно лаконичен или прост. Как и в связанном посте, вы в конечном итоге загрузите параметр (ldarg или ldarga, может быть, некоторые .s), а затем в зависимости от того, является ли элемент полем или свойством, с помощью ldfld или callvirt в свойстве getter. Около 3 строк, поэтому не огромный ; возможно что-то вроде:
static void EmitLoadPropertyOrField(ILGenerator il, Type type, string name)
{
// assumes that the target *reference* has already been loaded; only
// implements reference-type semantics currently
var member = type.GetMember(name, BindingFlags.Public | BindingFlags.Instance).Single();
switch (member)
{
case FieldInfo field:
il.Emit(OpCodes.Ldfld, field);
break;
case PropertyInfo prop:
il.EmitCall(OpCodes.Callvirt, prop.GetGetMethod(), null);
break;
default:
throw new InvalidOperationException();
}
}
Если вы пытаетесь сохранить сложность (или устали от InvalidProgramException
), другой жизнеспособный подход - использовать деревья выражений; тогда у вас есть еще много удобных функций, но, в частности, таких как:
var p = Expression.Parameter(typeof(Foo), "x");
var name = Expression.PropertyOrField(p, "Name");
// ...
var lambda = Expression.Lambda<YourDelegateType>(body, p);
var del = lambda.Compile();
Обратите внимание, что деревья выражений нельзя использовать во всех сценариях; например, они не могут быть использованы с TypeBuilder
; наоборот, они могут делать то, что IL-emit не может - например, в сценарии AOT ios, где IL-emit запрещен, они могут работать как дерево оценки отражения во время выполнения, поэтому все еще работает (но: медленнее). Они добавляют некоторую дополнительную обработку (сборку и последующий анализ дерева), но: они на проще , чем IL-emit, особенно для отладки.