C# Net标准中CompileToMethod的替代方案
我现在正在将一些使用表达式的库移植到C# Net标准中CompileToMethod的替代方案,c#,.net,.net-core,.net-standard,C#,.net,.net Core,.net Standard,我现在正在将一些使用表达式的库移植到.Net Core应用程序中,遇到了一个问题,即我的所有逻辑都基于LambdaExpression.CompileToMethod,这在中根本不存在。以下是示例代码: public static MethodInfo CompileToInstanceMethod(this LambdaExpression expression, TypeBuilder tb, string methodName, MethodAttributes attributes) {
.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);
...
}
publicstaticmethodinfo CompileToInstanceMethod(这个LambdaExpression表达式、TypeBuilder tb、stringmethodname、MethodAttributes)
{
...
var method=tb.DefineMethod($“u StaticProxy”,MethodAttributes.Private | MethodAttributes.Static,proxy.ReturnType,paramTypes);
表达式。编译方法(method);
...
}
是否有可能以某种方式重写它,以便能够使用表达式生成方法?我已经可以用Emit
来实现它,但是它非常复杂,我希望避免使用高级表达式
我尝试使用var method=expression.Compile().GetMethodInfo()代码>但在这种情况下,我得到一个错误:
System.InvalidOperationException:无法导入全局方法或
来自不同模块的字段
我知道我可以手动发出IL,但我需要将Expression
->转换为绑定到特定TypeBuilder
的MethodInfo
,而不是在其上构建自己的DynamicMethod
。这不是一个理想的解决方案,但如果您不想从头开始编写所有内容,则值得考虑:
如果您查看CompileToMethod
实现,您将看到它使用内部LambdaCompiler
类
如果你深入研究,你会发现LambdaCompiler
使用System.Reflection.Emit
将lambda转换成MethodInfo
System.Reflection.Emit
受.NET内核支持
考虑到这一点,我的建议是尝试重用LambdaCompiler
源代码。你可以找到它
此解决方案的最大问题是:
LambdaCompiler
分布在许多文件中,因此查找编译它所需的内容可能很麻烦
LambdaCompiler
可能使用一些.NET核心根本不支持的API
还有几点意见:
如果要检查哪个平台支持哪个API,请使用
如果您想查看.NET标准版本之间的差异,请使用网站
我在将一些代码移植到netstandard时遇到了同样的问题。我的解决方案是使用compile方法将lambda编译成Func,将Func存储在我添加到动态类型的静态字段中,然后在我的动态方法中,我只需从该静态字段加载并调用Func。这允许我使用LINQ表达式API而不是反射发射来创建lambda(这会很痛苦),但仍然让我的动态类型实现一个接口(这是我的场景的另一个要求)
感觉有点像黑客,但它可以工作,并且可能比尝试通过LambdaCompiler重新创建CompileToMethod功能更容易 试图使LambdaCompiler在.NET Core上工作
基于Michal Komorowski的回答,我决定尝试将LambdaCompiler
移植到.NET核心。你可以找到我的努力(GitHub链接)。事实上,该类分布在多个文件上是这里最小的问题之一。一个更大的问题是它依赖于.NET核心代码库中的内部部分
引用我在GitHub回购协议中的话:
不幸的是,这并非微不足道,因为(至少)以下问题:
- AppDomain.CurrentDomain.DefinedDynamicAssembly在.NET Core中不可用-AssemblyBuilder.DefinedDynamicAssembly替换为。这个答案描述了如何使用它
- Assembly.DefinitionInformationSource不可用
- 依赖内部方法和属性,例如BlockExpression.ExpressionCount、BlockExpression.GetExpression、BinaryExpression.IsLiftedLogical等
出于上述原因,试图将此工作作为一个独立的包来完成,实际上是徒劳的。唯一可行的方法是将其包含在.NETCore中
然而,由于其他原因,这是有问题的。我认为许可证是这里的绊脚石之一。其中一些代码可能是作为DLR工作的一部分编写的,而DLR本身也获得了Apache许可。一旦代码库中有第三方贡献者的贡献,重新授权它(到麻省理工学院,就像.NET核心代码库的其余部分一样)或多或少是不可能的
其他选择
我认为目前最好的选择是以下两种情况之一,具体取决于用例:
- 使用,可从NuGet(Apache 2.0-licensed)获得。这是授权的运行时,据我所知,这是唯一一种主动维护的DLR支持的语言。(IronRuby和IronJS似乎都被有效地抛弃了。)DLR允许您使用
Microsoft.Scripting.Ast.lambdaulder
定义lambda表达式;不过,IronPython似乎没有直接使用它。还有Microsoft.Scripting.解释器.LightCompiler
类,它似乎非常有趣
不幸的是,DLR的文档记录似乎很差。我想有一个wiki被引用了,但是它是离线的(可以通过下载CodePlex上的存档文件来访问)
- 使用Roslyn为您编译(动态)代码。这可能也有一点学习曲线;不幸的是,我自己对它还不是很熟悉
这似乎有相当多的策划链接,教程等:。我建议以此为出发点。如果您对动态构建方法特别感兴趣,那么这些方法似乎也值得一读:
她