可以使用Roslyn生成类似于DynamicMethod IL生成的动态方法

我一直在使用DynamiMethod来生成IL

method.GetILGenerator(); 

这很好用,但当然很难使用,因为你通常不想在C#这样的高级语言中使用低级别的IL。 现在,因为有罗斯林,我可以使用它。 我试图找出如何使用Roslyn做类似的事情:生成一个动态方法,然后为它创建一个委托。 我能做到的唯一方法是拥有这样的全class

 SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@" using System; namespace RoslynCompileSample { public class Writer { public void Write(string message) { Console.WriteLine(message); } } }"); 

然后我可以使用字符串连接插入我的方法而不是Write方法。 之后,在内存中生成动态程序集并加载,并使用reflection来获取所需的方法并生成委托。

这种方法似乎工作正常但对我的情况似乎有点过分,因为我需要使用多个独立的方法,导致大量的程序集被加载。

所以问题是:是否有一种简单的方法可以为Roslyn执行类似于动态方法的操作,这样我只能定义附加到类型的方法体? 如果没有,编译许多动态程序集有什么大的缺点(比如太多无法加载等等)

您可以使用CSharpScript类。 await CSharpScript.EvaluateAsync("1 + 2")只计算表达式。 您可以在Microsoft.CodeAnalysis.Scripting.CSharp包中找到它(目前只有预发行版)。 使用ScriptOptions(第二个参数)添加使用和程序集引用。

将表达式编译为委托:

 var func = CSharpScript.Create("1 + 3").CompileToDelegate() 

使用globals对象将某些内容传递给函数:

 await CSharpScript.Create("1 + x", ScriptOptions.Default.AddReferences(typeof(Program).Assembly), globalsType: typeof(ScriptGlobals)) .CreateDelegate() .Invoke(new 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>(new[] { parameter }, body); // define method var add42Delegate = lambdaExpression.Compile(); // compile to dynamic method 

您几乎可以使用它做任何事情,它比ILGenerator更舒适,并且包含在标准库中。

我想用ExpressionFunc来评论exyi的答案,但我没有足够的声誉。 所以这里是我的“答案”。

如果您只需要一个可以使用参数执行的一等公民代码,您可以像这样创建Lambda:

 Func add42 = number => number + 42; // Called like this: int theNumber46 = add42.Invoke(4); 

如果您需要实际的表达式树,还有一个简洁的快捷方式:

 Expression> add42 = number => number + 42; // Called like this: int theNumber46 = add42.Compile().Invoke(4); 

代码的唯一区别是,您使用Expression<..>包装了Func Expression<..> 。 概念上的区别在于,Lambda(或者本例中的Func<> ,但也有其他Lambdas)可以按原样执行,而Expression<>需要首先使用Compile()方法进行Compile() 。 但Expression保存有关语法树的信息,因此可用于EntityFramework中使用的IQueriable数据提供程序。

所以这一切都取决于你想用动态方法/ lamda / delegate做什么。