C# Roslyn能否用于生成类似于DynamicMethod IL生成的动态方法
我一直在使用DynamicMethod生成IL,使用C# Roslyn能否用于生成类似于DynamicMethod IL生成的动态方法,c#,.net,compilation,roslyn,reflection.emit,C#,.net,Compilation,Roslyn,Reflection.emit,我一直在使用DynamicMethod生成IL,使用 method.GetILGenerator(); 这很好,但当然很难使用,因为您通常不希望在像C#这样的高级语言中使用低级IL。既然有罗斯林,我想我可以用它来代替。我试图找出如何使用Roslyn做类似的事情:生成一个动态方法,然后为它创建一个委托。我能做到这一点的唯一办法就是像这样上完整的课 SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@" using System; namesp
method.GetILGenerator();
这很好,但当然很难使用,因为您通常不希望在像C#这样的高级语言中使用低级IL。既然有罗斯林,我想我可以用它来代替。我试图找出如何使用Roslyn做类似的事情:生成一个动态方法,然后为它创建一个委托。我能做到这一点的唯一办法就是像这样上完整的课
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@"
using System;
namespace RoslynCompileSample
{
public class Writer
{
public void Write(string message)
{
Console.WriteLine(message);
}
}
}");
然后,我可以使用字符串连接将我的方法插入其中,而不是Write方法。之后,在内存中生成并加载动态程序集,并使用反射来获取所需的方法并生成委托
这个方法似乎工作得很好,但对于我的案例来说似乎有点过分,因为我需要使用多个独立的方法,可能会导致大量的程序集被加载
所以问题是:有没有一种简单的方法可以为Roslyn做一些类似于DynamicMethod的事情,这样我就只能定义一个附加到类型的方法体?如果没有,编译许多动态程序集是否有什么大的缺点(比如太多的程序集无法加载等等)您可以使用
CSharpScript
类<代码>等待CSharpScript.EvaluateAsync(“1+2”)只计算表达式。您可以在Microsoft.CodeAnalysis.Scripting.CSharp软件包(当前仅为预发布版本)中找到它。使用ScriptOptions(第二个参数)添加使用和程序集引用
编译要委托的表达式:
var func = CSharpScript.Create<int>("1 + 3").CompileToDelegate()
var func=CSharpScript.Create(“1+3”).CompileToDelegate()
使用globals对象将某些内容传递给函数:
await CSharpScript.Create<int>("1 + x",
ScriptOptions.Default.AddReferences(typeof(Program).Assembly),
globalsType: typeof(ScriptGlobals))
.CreateDelegate()
.Invoke(new ScriptGlobals() { x = 4 });
等待CSharpScript.Create(“1+x”,
ScriptOptions.Default.AddReferences(typeof(Program.Assembly)),
globalsType:typeof(ScriptGlobals))
.CreateDelegate()
.Invoke(新的ScriptGlobals(){x=4});
我还有一个办法解决你的问题,那就是根本不用Roslyn。您描述了使用
ILGenerator
发出IL是很烦人的。然而.NET Framework有内置的语义树,可以编译为动态方法。它们位于Linq.Expression
命名空间中,也用于Linq提供程序
var parameter = Expression.Parameter(typeof(int), "a"); // define parameter
var body = Expression.Add(parameter, Expression.Constant(42)); // sum parameter and number
var lambdaExpression = Expression.Lambda<Func<int, int>>(new[] { parameter }, body); // define method
var add42Delegate = lambdaExpression.Compile(); // compile to dynamic method
var parameter=Expression.parameter(typeof(int),“a”);//定义参数
var body=Expression.Add(参数,Expression.Constant(42));//求和参数和数
var lambdaExpression=Expression.Lambda(新[]{parameter},body);//定义方法
var add42Delegate=lambdaExpression.Compile();//编译为动态方法
你几乎可以用它做任何事情,它比ILGenerator舒适得多,并且包含在标准库中。我想用
表达式和函数来评论exyi的答案,但我没有足够的声誉。所以我的“答案”来了
如果您所需要的只是一段可以使用参数执行的一流公民代码,那么您可以简单地创建Lambda,如下所示:
Func<int, int> add42 = number => number + 42;
// Called like this:
int theNumber46 = add42.Invoke(4);
Func add42=number=>number+42;
//这样称呼:
int theNumber46=add42.Invoke(4);
如果需要实际的表达式树,还有一个简洁的快捷方式:
Expression<Func<int, int>> add42 = number => number + 42;
// Called like this:
int theNumber46 = add42.Compile().Invoke(4);
表达式add42=number=>number+42;
//这样称呼:
int theNumber46=add42.Compile().Invoke(4);
代码中唯一的区别是,使用表达式
包装Func
。概念上的区别在于,Lambda(或本例中的Func
,但也有其他Lambda)可以按原样执行,而表达式
需要首先使用Compile()
方法编译。但是表达式
保存有关语法树的信息,因此可以用于EntityFramework中使用的iQuery
数据提供程序
所以这一切都取决于你想用你的动态方法/lamda/delegate做什么。Roslyn过去有一个DynamicMethod
发射器,但是DynamicMethod
有太多的限制,所以它被删除了。这是一个遗憾,因为它应该提供很好的特性,而不会干扰程序集加载……只有一个小问题。CSharpScript会暂时将内存使用量增加到1 GB左右,但大部分都是在编译后进行清理。@mswietlicki内存使用量的增加通常是由于“全局”类的大量依赖项/引用所致。我想自然的本能是在项目/dll中创建一个“全局”类型作为另一个类(我创建了),但这意味着Roslyn编译器必须加载所有这些依赖项才能构建脚本。一个巧妙的技巧是将您的“全局”类型托管在一个单独的“脚本”dll中,具有最小的外部依赖性。编译时间和内存将。。。那就自己试试看吧。Roslyn doc中的一个小细节。