.Net Standard中CompileToMethod的替代品

Ale*_*kiy 16 .net c# .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);

    ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

System.InvalidOperationException:无法从其他模块导入全局方法或字段.

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

Mic*_*ski 7

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

  1. 如果你看看CompileToMethod实现,你会发现它使用了内部LambdaCompiler类.
  2. 如果你挖得更深,你预订购看到LambdaCompiler使用System.Reflection.Emit到lambda表达式转换成MethodInfo.
  3. System.Reflection.Emit .NET Core支持.
  4. 考虑到这一点,我的主张是尝试重用LambdaCompiler源代码.你可以在这里找到它.

该解决方案的最大问题是:

  1. LambdaCompiler 在许多文件中传播,因此找到编译它所需的内容可能很麻烦.
  2. LambdaCompiler 可能会使用.NET Core不支持的某些API.

一些额外的评论:

  1. 如果要检查哪个平台支持哪个API,请使用.NET API目录.
  2. 如果您想查看.NET标准版本之间的差异,请使用站点.


Per*_*erg 2

尝试让 LambdaCompiler 在 .NET Core 上运行

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

引用我自己在上面的 GitHub 存储库中的内容:

不幸的是,由于(至少)以下问题,这并非易事:

  • AppDomain.CurrentDomain.DefineDynamicAssembly 在 .NET Core 中不可用 - AssemblyBuilder.DefineDynamicAssembly 取代了它。这个 SO 答案描述了如何使用它。

  • Assembly.DefineVersionInfoResource 不可用。

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

由于上述原因,尝试将其作为一个独立的包来工作本质上是没有成果的。实现此功能的唯一现实方法是将其包含在 .NET Core 中。

然而,由于其他原因,这是有问题的。我相信许可是这里的绊脚石之一。其中一些代码可能是作为 DLR 工作的一部分编写的,它本身已获得 Apache 许可。一旦您在代码库中获得了第 3 方贡献者的贡献,重新授权它(像 .NET Core 代码库的其余部分一样,授予 MIT)就或多或少是不可能的。

其他选项

我认为,根据用例,目前您最好的选择是以下两个之一:

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