Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have been using DynamiMethod to generate the IL using

method.GetILGenerator();

This works well but is of course very hard to use since you generally don't want to work with low level IL in a high level language like C#. Now since there is Roslyn I though I can use that instead. I have tried to figure out how to use Roslyn to do similar thing: generate a dynamic method and then create a delegate for it. The only way I was able to do that is to have full class like this

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

namespace RoslynCompileSample
{
    public class Writer
    {
        public void Write(string message)
        {
            Console.WriteLine(message);
        }
    }
}");

Then instead of the Write method I can insert my method inside using string concatenation. After that dynamic assembly is generated in memory and loaded and reflection is used to get the required method and generate the delegate.

This method seems to work fine but seems a bit of an overkill for my case as I will need to use multiple independent methods possible leading to lots of assemblies being loaded.

So the question is: Is there an easy way to do something similar to dynamic method for Roslyn, so that I can only define a body of the method attached to a type? If not, is there any big drawback in compiling many dynamic assemblies (like too many can't be loaded, etc...)

like image 945
Ilya Chernomordik Avatar asked Aug 19 '15 13:08

Ilya Chernomordik


2 Answers

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.

like image 162
exyi Avatar answered Nov 07 '22 11:11

exyi


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 IQueryable data providers as used in Entity Framework.

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

like image 33
Marvin Ede Avatar answered Nov 07 '22 11:11

Marvin Ede