【问题标题】:C# How to call LINQ's First method with predicate using Reflection.EmitC# 如何使用 Reflection.Emit 调用带有谓词的 LINQ 的第一个方法
【发布时间】:2020-12-01 21:06:28
【问题描述】:

我试图将我的头包裹在 Reflection.Emit 周围,我正在玩弄它以了解它是如何工作的。

我正在尝试实现这个方法:

public static object GetTableKeyValue(object tableValue) => tableValue.GetType().GetProperties().First(property => property.GetCustomAttribute<KeyAttribute>() is not null).GetValue(tableValue);

这是我到目前为止所做的:

public static object GetTableKeyValueReflectionEmit(object val)
        {
            var getTableKeyValue = new DynamicMethod("GetTableKeyValueReflectionEmit", typeof(object), new Type[] { typeof(object) }, typeof(object).Module);
            getTableKeyValue.DefineParameter(1, ParameterAttributes.In, "tableValue");
            var il = getTableKeyValue.GetILGenerator(256);

            il.Emit(OpCodes.Ldarg_0);
            il.EmitCall(OpCodes.Call, typeof(object).GetMethod(nameof(object.GetType)), null);
            il.EmitCall(OpCodes.Call, typeof(Type).GetMethod(nameof(Type.GetProperties), new Type[] { }), null);
            Func<PropertyInfo, bool> predicate = property => (!property.GetCustomAttribute<KeyAttribute>().Equals(null));
            // im stuck here
            il.EmitCall(OpCodes.Call, typeof(Enumerable).GetMember(nameof(Enumerable.First)).OfType<MethodInfo>().First(method => method.GetParameters().Length == 1), new Type[] { typeof(Func<PropertyInfo, bool>) });
            il.EmitCall(OpCodes.Call, typeof(PropertyInfo).GetMethod(nameof(PropertyInfo.GetValue), new Type[] { typeof(object) }), new Type[] { typeof(object) });

            il.Emit(OpCodes.Ret);

            var getTableKeyValueDelegate = (GetTableKeyValueDelegate)getTableKeyValue.CreateDelegate(typeof(GetTableKeyValueDelegate));
            return getTableKeyValueDelegate(val);
        }

我无法理解如何定义 Func 类型的谓词并将其传递给 First 方法,而且我无法真正找到有关 Reflection.Emit 的好信息,我想这样做并不常见。

我们将不胜感激。

【问题讨论】:

  • 使用 LINQPad,您可以查看代码的 IL 并查看编译器生成的内容。不过,通常情况下,我建议使用Expression.Compile 而不是Reflection.Emit
  • 我已经使用 Expression.Compile 编写了它,只是尝试对 Reflection.Emit 执行相同操作以查看差异。
  • 或许il.Emit(Opcodes.Ldftn, predicate.GetMethodInfo())?

标签: c# .net reflection system.reflection reflection.emit


【解决方案1】:

这似乎对我有用:

public static object GetTableKeyValueReflectionEmit(object val) {
    var getTableKeyValue = new DynamicMethod("GetTableKeyValueReflectionEmit", typeof(object), new Type[] { typeof(object) }, typeof(object).Module);
    getTableKeyValue.DefineParameter(1, ParameterAttributes.In, "tableValue");
    var il = getTableKeyValue.GetILGenerator(256);

    il.Emit(OpCodes.Ldarg_0);
    il.EmitCall(OpCodes.Call, typeof(object).GetMethod(nameof(object.GetType)), null);
    il.EmitCall(OpCodes.Call, typeof(Type).GetMethod(nameof(Type.GetProperties), new Type[] { }), null);
    Func<PropertyInfo, bool> predicate = property => (!property.GetCustomAttribute<KeyAttribute>().Equals(null));
    il.Emit(OpCodes.Ldftn, predicate.GetMethodInfo());
    var miFirstGeneric = typeof(Enumerable).GetMember(nameof(Enumerable.First)).OfType<MethodInfo>().First(method => method.GetParameters().Length == 1);
    var miFirst = miFirstGeneric.MakeGenericMethod(typeof(PropertyInfo));
    il.Emit(OpCodes.Call, miFirst);
    il.Emit(OpCodes.Call, typeof(PropertyInfo).GetMethod(nameof(PropertyInfo.GetValue), new Type[] { typeof(object) }));

    il.Emit(OpCodes.Ret);

    var getTableKeyValueDelegate = (GetTableKeyValueDelegate)getTableKeyValue.CreateDelegate(typeof(GetTableKeyValueDelegate));
    return getTableKeyValueDelegate(val);
}

【讨论】:

  • 我在运行您的代码时遇到此异常: System.ExecutionEngineException: 'Exception of type 'System.ExecutionEngineException' was throwed.'
  • @MeydanOzeri 在 LINQPad 中为我工作?
  • @MeydanOzeri 我明白你的意思...Ldftn 仍然有问题。
猜你喜欢
  • 2016-09-22
  • 1970-01-01
  • 1970-01-01
  • 2010-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多