.Net Standard中CompileToMethod的替代品

时间:2017-01-07 10:20:19

标签: c# .net .net-core .net-standard

我现在正在移植一些使用表达式到.Net Core应用程序的库,并遇到一个问题,我的所有逻辑都基于LambdaExpression.CompileToMethod,而这个问题根本就没有了。这是示例代码:

public static MethodInfo CompileToInstanceMethod(this LambdaExpression expression, TypeBuilder tb, string methodName, MethodAttributes attributes)
{
    ...

    var method = tb.DefineMethod($"<{proxy.Name}>__StaticProxy", MethodAttributes.Private | MethodAttributes.Static, proxy.ReturnType, paramTypes);
    expression.CompileToMethod(method);

    ...
}

是否有可能以某种方式重写它以使用表达式生成方法成为可能?我已经可以使用Emit来完成它,但它非常复杂,我想避免它支持高级表达式。

我尝试使用var method = expression.Compile().GetMethodInfo();但在这种情况下我收到错误:

  

System.InvalidOperationException:无法导入全局方法或   来自不同模块的字段。

我知道我可以手动发出IL,但我需要完全转换Expression - &gt;将MethodInfo绑定到特定TypeBuilder,而不是在其上构建自己DynamicMethod

3 个答案:

答案 0 :(得分:6)

这不是一个理想的解决方案,但如果您不想从头开始编写所有内容,那么值得考虑:

  1. 如果您查看CompileToMethod实施,您会看到它使用内部LambdaCompiler类。
  2. 如果你深入挖掘,你会发现LambdaCompiler使用System.Reflection.Emit将lambda转换为MethodInfo
  3. System.Reflection.Emit受.NET Core支持。
  4. 考虑到这一点,我的主张是尝试重用LambdaCompiler源代码。你可以找到它here
  5. 此解决方案的最大问题是:

    1. LambdaCompiler分布在许多文件中,因此找到编译它所需的内容可能很麻烦。
    2. LambdaCompiler可能会使用.NET Core不支持的某些API。
    3. 另外一些评论:

      1. 如果您想检查哪个平台支持哪个API .NET API Catalog
      2. 如果您想查看.NET标准版本之间的差异,请使用this site。

答案 1 :(得分:1)

将一些代码移植到netstandard时遇到了同样的问题。我的解决方案是使用Compile方法将lambda编译为Func,将Func存储在我添加到动态类型的静态字段中,然后在我的动态方法中,我只需从该静态字段加载并调用Func。这允许我使用LINQ Expression API而不是反射发射来创建lambda(这本来很痛苦),但仍然让我的动态类型实现一个接口(这是我的场景的另一个要求)。

感觉有点像黑客,但它有效,并且可能比通过LambdaCompiler重新创建CompileToMethod功能更容易。

答案 2 :(得分:1)

试图让LambdaCompiler在.NET Core上运行

基于Michal Komorowski的回答,我决定尝试将LambdaCompiler移植到.NET Core。您可以找到我的努力here(GitHub链接)。实际上,该类分布在多个文件中的事实是这里最小的问题之一。更大的问题是它依赖于.NET Core代码库中的内部部分。

从上面的GitHub存储库中引用自己:

不幸的是,由于(至少)以下问题,它是不平凡的:

  • AppDomain.CurrentDomain.DefineDynamicAssembly在.NET Core中不可用-AssemblyBuilder.DefineDynamicAssembly替换为is。这样的答案说明了如何使用它。

  • Assembly.DefineVersionInfoResource不可用。

  • 依赖于内部方法和属性,例如BlockExpression.ExpressionCount,BlockExpression.GetExpression,BinaryExpression.IsLiftedLogical等。

由于上述原因,尝试将其作为独立程序包进行工作本质上是徒劳的。使这项工作唯一可行的方法就是将其包含在.NET Core中。

但是,由于其他原因,这是有问题的。我相信许可是这里的绊脚石之一。其中一些代码可能是DLR工作的一部分,而DLR工作本身就是Apache许可的。一旦您在代码库中获得了第三方贡献者的贡献,(或与.NET Core代码库的其余部分一样)将其重新许可给MIT便变得或多或少了。

其他选项

我认为,根据使用情况,目前最好的选择是以下两种方式之一:

还有第三种选择,对我们大多数人来说可能不感兴趣: