有没有办法将 lambda 表达式(有效地)转换为函数指针,委托 *<?,?,?,?,>?



我目前在这里执行此代码:

Fp = (delegate* unmanaged<????bool>)Expression.Lambda(func).Compile().Method.MethodHandle.GetFunctionPointer();

但实际上,我想避免临时创建DelegateExpression.Lambda(func).Compile(),而是立即转到这样的东西:

Expression.Lambda(func).MakeFuncPointer()

这将是很酷的,所以我们可以立即将其转换为它,而不需要创建临时委托,这是额外的分配成本。

<,,,,><???>是Lambda的精确类型匹配的占位符,您可以自由地假设它们都是相同的签名!

显然,我得到了一个运行时异常:;请求的操作对于DynamicMethod"无效;。

函数指针和委托之间有一个显著的区别,即委托不仅包含对函数的引用,还可以包含this引用(或静态方法中的第一个参数(,因此您可以使用它让代码在捕获的状态下操作(这被称为闭合委托(。函数指针不存储任何状态,因此它更简单,但在某些情况下也受到限制。

这一点很重要,因为不能保证一个特定的表达式只能根据代码进行编译。如果对非基元值使用Expression.Constant之类的东西,则对象必须与表达式一起存储,因此最终委托存储编译后的方法和闭包。即使您注意不要创建任何闭包,仍然有可能生成一个闭合的委托,因为并非所有平台在调用Compile时都会编译表达式。如果不能生成IL,则对表达式进行解释,在这种情况下,必须关闭委托才能引用表达式本身。

现在在.NET Framework上,有了LambdaExpression.CompileToMethod,它可以用来省略委托创建,而使用MethodBuilder(但您必须构建整个程序集(。这不在.NET Core上,因为前面提到的表达式必须被解释的可能性。

总而言之,在大多数情况下都需要委托来生成编译表达式的可移植代码。现在,我实际上已经提出了一种方法,如果可能的话,可以从委托中提取指针,但如果它被关闭,可能会有其他问题(我认为它甚至比使用委托更慢(。

如果委托是打开的,您可以使用反射来获得存储的指针,但不同平台上的内部字段不同:

static readonly System.Reflection.FieldInfo methodPtr =
// .NET
typeof(Delegate).GetField("_methodPtrAux", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic) ??
// Mono
typeof(Delegate).GetField("interp_method", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

最新更新