加载动态编译的程序集的符号

时间:2016-04-30 09:10:24

标签: c# visual-studio roslyn

我正在为我的应用添加脚本编写功能。 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();
        }

1 个答案:

答案 0 :(得分:4)

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

您可以使用SourceLink从生成的PDB(首先将其保存到磁盘中)转储校验和:

sourcelink checksums -p <pdbfile>

您可以将转储中脚本文件的值与您在代码中计算的源文件的哈希值进行比较。除非这两者不匹配,否则Visual Studio的调试器将无法正确获取脚本文件。

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

因此,如果我的预感是正确的,那么获得SourceTree这样的问题也可以解决您的问题:

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