2016-04-30 53 views
1

我正在为我的应用程序添加脚本编写的可能性。 Init方法加载脚本,编译它并调用脚本Init方法。我希望能够将Visual Studio调试器附加到我的应用程序,并在IDE中以通常的方式在脚本中添加断点。为动态编译的程序集加载符号

Visual Studio说:加载'i0uu5bcn.vhy'。找不到或打开PDB文件。

如果使用类似下面的断点:System.Diagnostics.Debugger.Break();

public static string[] Init(string scriptPath, params object[] parameters) 
     { 
      List<string> errors = new List<string>(); 

      SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(File.ReadAllText(scriptPath), null, scriptPath); 

      SyntaxTree encoded = CSharpSyntaxTree.Create(syntaxTree.GetRoot() as CSharpSyntaxNode, null, scriptPath, System.Text.Encoding.UTF8); 

      string assemblyName = Path.GetRandomFileName(); 

      MetadataReference[] references = new MetadataReference[] 
      { 
       MetadataReference.CreateFromFile(typeof(object).Assembly.Location), 
       MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location) 
      }; 

      CSharpCompilation compilation = CSharpCompilation.Create(
       assemblyName, 
       syntaxTrees: new[] { encoded }, 
       references: references, 
       options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); 

      Assembly finalAssembly = null; 

      using (var symbols = new MemoryStream()) 
      { 
       using (var ms = new MemoryStream()) 
       { 
        EmitResult result = compilation.Emit(ms, symbols); 

        if (!result.Success) 
        { 
         IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic => 
          diagnostic.IsWarningAsError || 
          diagnostic.Severity == DiagnosticSeverity.Error); 

         foreach (Diagnostic diagnostic in failures) 
         { 
          errors.Add($"{diagnostic.Id}: {diagnostic.GetMessage()}"); 
         } 
        } 
        else 
        { 
         ms.Seek(0, SeekOrigin.Begin); 
         symbols.Seek(0, SeekOrigin.Begin); 

         finalAssembly = Assembly.Load(ms.ToArray(), symbols.ToArray()); 

         Type type = finalAssembly.DefinedTypes.First().AsType(); 
         object obj = Activator.CreateInstance(type); 
         type.InvokeMember("Init", 
          BindingFlags.Default | BindingFlags.InvokeMethod, 
          null, 
          obj, 
          parameters); 
        } 
       } 
      } 

      return errors.ToArray(); 
     } 

回答

2

确保该文件实际上是UTF8编码的。编码用于获取生成PDB时使用的散列函数的输入字节。请注意,Encoding.UTF8假定文件有BOM

可以使用SourceLink转储从生成PDB(它保存到硬盘的第一个...)校验:

sourcelink checksums -p <pdbfile> 

您可以针对散列转储比较您的脚本文件中的值的您在代码中计算的源文件。除非这两者不匹配,否则Visual Studio的调试器将不会正确拾取脚本文件。

另请注意,如果您使用SourceText.From(Stream, Encoding),它会尝试detect the correct encodingfor you

所以,如果我的预感是正确的,得到了​​SourceTree这应该解决您的问题,以及:

SyntaxTree encoded; 
using(var stream = File.OpenRead(scriptPath)) 
{ 
    SourceText text = SourceText.From(stream, Encoding.UTF8); 
    encoded = CSharpSyntaxTree.ParseText(text, null, scriptPath); 
}