2013-07-16 31 views
3

在我投入大量時間瞭解roslyn編譯器服務之前,我想問問下列情況是否適用於roslyn。是否有可能編譯程序集而不必將任何內容寫入磁盤並執行它?我基於元模型生成完整的解決方案,並且我想要將它編譯並執行它。 Roslyn可能嗎?Roslyn:從元模型創建程序集

+0

爲什麼很重要,你不寫什麼盤? – svick

+0

@svick:沒有試圖粗魯或任何事情,但爲了回答這個問題,爲什麼重要的是不要寫任何東西到磁盤上並不重要。 – epitka

+2

這可能沒有關係,但很難判斷你是否不告訴我們。很多時候,人們會陷入[XY問題](http://meta.stackexchange.com/q/66377/130186):不問實際的問題。因此,如果你清楚地說明*你實際上正在努力做什麼,而不僅僅是*你想要做什麼,這會有所幫助。 – svick

回答

1

是的。我自己在做這個。這裏是如何做到這一點的例子:

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; 
    } 
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()); 
} 
相關問題