Search code examples
c#.netcompilationcode-analysis

Dynamically compile code from .Net Standard 2.0


I'm developing a .Net Standard 2.0 library offering dynamic compilation but there are always missing references.

A consumer using .Net Core, calls an Api with his source code as text, implementing a known interface by the library.

//Consumer Program.cs
using DynamicCompilationNetStandard2._0;

var source = """
using DynamicCompilationNetStandard2._0;
using System.Linq.Expressions;

namespace Consumer
{
    public class MyTask : ITask
    {
        public void CanRun<T>(Expression<Func<T, bool>> predicate)
        {
        }

        public void Run()
        {
            Console.WriteLine("Finished");
        }
    }
}
    """;

Executor.Execute(source);

The library's Executor class:

using Basic.Reference.Assemblies;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Reflection;
using System.Linq.Expressions;

namespace DynamicCompilationNetStandard2._0;

public static class Executor
{
    public static void Execute(string source)
    {
        var syntaxTree = SyntaxFactory.ParseSyntaxTree(source);
        var compilation = CSharpCompilation.Create(assemblyName: Path.GetRandomFileName())            
            .WithReferenceAssemblies(ReferenceAssemblyKind.NetStandard20)
            .AddReferences(
                MetadataReference.CreateFromFile(typeof(ITask).Assembly.Location))
            .AddReferences(ReferenceAssemblies.NetStandard20)
            .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
            .AddSyntaxTrees(syntaxTree);

        using (var ms = new MemoryStream())
        {
            var result = compilation.Emit(ms);
            if (!result.Success)
            {
                throw new Exception(result.ToString()); //CRASH
            }

            ms.Seek(0, SeekOrigin.Begin);
            var assembly = Assembly.Load(ms.ToArray());

            try
            {
                var types = assembly.GetTypes();
            }
            catch (Exception ex)
            {
                throw; //CRASH
            }

            dynamic task = assembly.CreateInstance("Consumer.MyTask");
            task.Run();
        }
    }
}

public interface ITask
{
    void CanRun<T>(Expression<Func<T, bool>> predicate);
    void Run();
}

I'm using basic-reference-assemblies to add references to reference assemblies instead of implementations. Still I get theses errors: reference errors

How can I import missing references and fixing this simple project? Here is the source code: https://github.com/adampaquette/DynamicCompilationTests Thanks!


Solution

  • Ok the problem was an implicit reference to System. After adding using System; in the source string, it worked.