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

Ily*_*dik 7 .net c# compilation reflection.emit roslyn

我一直在使用DynamiMethod来生成IL

method.GetILGenerator();
Run Code Online (Sandbox Code Playgroud)

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

SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@"
using System;

namespace RoslynCompileSample
{
    public class Writer
    {
        public void Write(string message)
        {
            Console.WriteLine(message);
        }
    }
}");
Run Code Online (Sandbox Code Playgroud)

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

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

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

exy*_*xyi 2

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

编译表达式以委托:

var func = CSharpScript.Create<int>("1 + 3").CompileToDelegate()
Run Code Online (Sandbox Code Playgroud)

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

await CSharpScript.Create<int>("1 + x", 
     ScriptOptions.Default.AddReferences(typeof(Program).Assembly),
     globalsType:  typeof(ScriptGlobals))
    .CreateDelegate()
    .Invoke(new ScriptGlobals() { x = 4 });
Run Code Online (Sandbox Code Playgroud)

  • @mswietlicki 内存使用量的增加通常是由于“全局”类的大量依赖项/引用造成的。我想自然的本能是在你的项目/dll 中创建一个“全局”类型作为又一个类(我就是这么做的),但这意味着 Roslyn 编译器必须加载所有这些依赖项才能构建你的脚本。一个巧妙的技巧是将“全局”类型托管在一个单独的“脚本”dll 中,并具有最少的外部依赖性。编译时间和内存只会......好吧,亲自尝试一下。罗斯林文档中严重遗漏了一个小细节。 (2认同)