c# - 如何在当前 Visual Studio 主机内的 Visual Studio 扩展中调试使用 Roslyn 编译的代码?

标签 c# debugging roslyn visual-studio-extensions

我有一个 Visual Studio 扩展,它使用 Roslyn 在当前打开的解决方案中获取一个项目,编译它并从中运行方法。项目可以由程序员修改。

我已经从当前的 VisualStudioWorkspace 成功编译了一个 Visual Studio 扩展中的项目。

    private static Assembly CompileAndLoad(Compilation compilation)
    {
        using (MemoryStream dllStream = new MemoryStream())
        using (MemoryStream pdbStream = new MemoryStream())
        {
            EmitResult result = compilation.Emit(dllStream, pdbStream);

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

                string failuresException = "Failed to compile code generation project : \r\n";

                foreach (Diagnostic diagnostic in failures)
                {
                    failuresException += $"{diagnostic.Id} : {diagnostic.GetMessage()}\r\n";
                }

                throw new Exception(failuresException);
            }
            else
            {

                dllStream.Seek(0, SeekOrigin.Begin);
                return AppDomain.CurrentDomain.Load(dllStream.ToArray(), pdbStream.ToArray());

            }
        }
    }

然后我可以在当前域中加载程序集,获取它的类型并调用方法。

问题是如果加载解决方案的当前配置是调试,我需要允许程序员放置断点。

我需要通过扩展在当前 Visual Studio 主机中运行一些代码,并允许在当前 Visual Studio 实例中对其进行调试。

最佳答案

看来这实际上是不可能的。

当前visual studio实例无法 self 调试。

我尝试使用 roslyn 创建控制台应用程序,将其附加到调试器,然后从中运行生成代码。但是 VisualStudioWorkspace 仅在 VisualStudio 内部可用(不可序列化且不可通过 DTE com 接口(interface)使用)。所以剩下的唯一解决方案是使用 MBBuildWorkspace。由于它的行为与 Visual Studio 工作区不同,我放弃了该项目。

这是我的代码以供进一步引用:

Process vsProcess = Process.GetCurrentProcess();

string solutionPath = CurrentWorkspace.CurrentSolution.FilePath;

SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText($@"
            using System;
            using System.Threading.Tasks;

            namespace CodeGenApplication
            {{
                public class Program 
                {{
                    public static void Main(string[] args) 
                    {{

                    Console.ReadLine();
                    int vsProcessId = Int32.Parse(args[0]);
                    CodeGenApp.Test(""{solutionPath.Replace(@"\", @"\\")}"", ""{projectName}"", ""{_codeGenProjectName}"");
                    Console.ReadLine();
                    }}
                }}
            }}");

string assemblyName = Path.GetRandomFileName();

Project codeGenProject = CurrentWorkspace.CurrentSolution.Projects.Where(x => x.Name == _codeGenProjectName).FirstOrDefault();

List<MetadataReference> references = codeGenProject.MetadataReferences.ToList();

CSharpCompilation compilation = CSharpCompilation.Create(

    assemblyName,
    syntaxTrees: new[] { syntaxTree },
    references: references,
    options: new CSharpCompilationOptions(OutputKind.ConsoleApplication));

// Emit assembly to streams.
EmitResult result = compilation.Emit("CodeGenApplication.exe", "CodeGenApplication.pdb");

if (!result.Success)
{
    IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
        diagnostic.IsWarningAsError ||
        diagnostic.Severity == DiagnosticSeverity.Error);
}
else
{
    Process codeGenProcess = new Process();
    codeGenProcess.StartInfo.FileName = "CodeGenApplication.exe";
    codeGenProcess.StartInfo.Arguments = vsProcess.Id.ToString();
    codeGenProcess.StartInfo.UseShellExecute = false;
    codeGenProcess.StartInfo.CreateNoWindow = true;
    codeGenProcess.StartInfo.LoadUserProfile = true;
    codeGenProcess.StartInfo.RedirectStandardError = true;
    codeGenProcess.StartInfo.RedirectStandardInput = true;
    codeGenProcess.StartInfo.RedirectStandardOutput = false;
    codeGenProcess.Start();
    foreach (EnvDTE.Process dteProcess in _dte.Debugger.LocalProcesses)
    {
        if (dteProcess.ProcessID == codeGenProcess.Id)
        {
            dteProcess.Attach();
        }
    }
    codeGenProcess.StandardInput.WriteLine("Start");
}

关于c# - 如何在当前 Visual Studio 主机内的 Visual Studio 扩展中调试使用 Roslyn 编译的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34625059/

相关文章:

c# - 用于查找和删除重复单词的正则表达式

python - Django 在托管应用程序 pythonanywhere 上打印语句/调试

c# - Roslyn - 查明被调用的方法是否调用了方法

c# - Roslyn 可以编译 await 关键字吗?

c# - Roslyn 模型是否以 C#/VB.NET 为中心以至于现在和将来都无法进行 XAML 分析?

c# - AuthenticateAsServer 不接受 PEM 格式的证书

c# - 通用委托(delegate)的使用

c# - 目标数组不够长。检查目标索引和长度以及数组的下限

php - 在 laravel 5 中,如何从外部类访问 Command 类方法?

c# - 与 ****** 的网络连接已丢失。调试将被中止