3

在我投入大量时间学习 roslyn 编译器服务之前,我想问一下 roslyn 是否可以实现以下场景。是否可以编译程序集而无需将任何内容写入磁盘并执行它?我基于元模型生成完整的解决方案,我想接受它并编译它并执行它。罗斯林有可能吗?

4

2 回答 2

3

这是一个稍微轻一点的版本:

// Some standard references most projects use
var references = new List<MetadataReference>
{
    MetadataReference.CreateAssemblyReference("mscorlib"),
    MetadataReference.CreateAssemblyReference("System"),
    MetadataReference.CreateAssemblyReference("System.Linq"),
    new MetadataFileReference(this.GetType().Assembly.Location)
};

// The MyClassInAString is where your code goes
var syntaxTree = SyntaxTree.ParseText(MyClassInAString);

// Use Roslyn to compile the code into a DLL
var compiledCode = Compilation.Create(
    "MyAssemblyName",
    options: new CompilationOptions(OutputKind.DynamicallyLinkedLibrary),
    syntaxTrees: syntaxTree,
    references: references;
    );

// Now read the code into a memory stream. You can then load types out of the assembly with reflection
Assembly assembly;
using (var stream = new MemoryStream())
{
    EmitResult compileResult = compiledCode.Emit(stream);
    if (!compileResult.Success)
    {
        throw new InvalidOperationException("The assembly could not be built, there are {0} diagnostic messages.".FormatWith(compileResult.Diagnostics.Count()));
    }
    assembly = Assembly.Load(stream.GetBuffer());
}
于 2014-01-30T16:04:06.790 回答
1

Yes. I am doing this myself. Here is a sample on how to do it:

    public void CompileCode(programString){
        // Now that we have a compiled program we can actually compile it...
        // Program parsing code...
        SyntaxTree programSyntaxTree =  
          SyntaxTree.ParseText(programString);
        const string name = "CompiledProgram.dll";
        var compilation = Compilation.Create(name,
          options: new CompilationOptions(OutputKind.DynamicallyLinkedLibrary),
          syntaxTrees: new[] {
            programSyntaxTree
          },
          references: new[]{
            new MetadataFileReference(typeof(object).Assembly.Location)
          }
        );

        var modBuilder = BuildModuleBuilder();
        ReflectionEmitResult result = compilation.Emit(modBuilder);
        foreach (Diagnostic c in result.Diagnostics) {
            Console.WriteLine("D: {0}", c.ToString());
        }
        if (result.Diagnostics.LongCount() > 0) return false;
        this.builtModule = modBuilder;
    }

    private ModuleBuilder BuildModuleBuilder() {
        // Get the current application domain for the current thread.
        var currentDomain = AppDomain.CurrentDomain;
        var assemblyName = new AssemblyName {Name = "TempAssembly"};

        // Define a dynamic assembly in the current application domain.
        this.assemblyBuilder = currentDomain.DefineDynamicAssembly(
           assemblyName,
           AssemblyBuilderAccess.RunAndCollect
        );

        // Define a dynamic module in this assembly.
        var moduleBuilder = this.assemblyBuilder.DefineDynamicModule("TempModule");
        return moduleBuilder;
    }

    public Delegate RunCompiledProgram() {
        if (this.builtModule == null) return null;

        var type = this.builtModule.GetType("ProgramCompiler.BuiltProgram");
        var methodInfo = type.GetMethod("Eval");
        object o = Activator.CreateInstance(type, null, null);

        Delegate test = (BuiltProg) Delegate.CreateDelegate(
          typeof(BuiltProg), o, methodInfo, false
        );
        return test;
    }
于 2013-07-17T19:09:54.443 回答