Can Roslyn be used to generate dynamic method similar to DynamicMethod IL generation

拈花ヽ惹草 提交于 2019-12-04 06:16:52

You can use CSharpScript class. await CSharpScript.EvaluateAsync("1 + 2") just evaluates the expression. You can find it in Microsoft.CodeAnalysis.Scripting.CSharp package (currently only prerelease version). Add usings and assembly references using ScriptOptions (second parameter).

Compile expression to delegate:

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

Passing something to the function using globals object:

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

I have one more idea how to solve your problem, that does not use Roslyn at all. You described it's annoying to emit IL using ILGenerator. However .NET Framework has build-in semantic trees, that can be compiled to dynamic methods. They live in Linq.Expression namespace and are also used in Linq providers.

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

You can do almost anything using it, it's much more comfortable than ILGenerator and is included in standard library.

I'd like to comment on exyi's answer with Expression and Func<int,int>, but I don't have enough reputation. So here comes my "answer" instead.

If all you need is an first-class citizen piece of code that you can execute with parameters, you can simply create the Lambda like this:

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

If you need to have the actual expression tree, there is a neat shortcut as well:

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

The only difference in code is, that you wrapped the Func<int,int> with an Expression<..>. The conceptual difference is, that a Lambda (or Func<> in this example, but there are other Lambdas as well) can be executed as is, whereas an Expression<> needs to be compiled first with the Compile() method. But the Expression holds information about the syntax tree and can therefore be used for IQueriable data providers as used in EntityFramework.

So it all depends on what you want to do with your dynamic method/lamda/delegate.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!