在调试可视化工具中在运行时检测源语言

Zev*_*itz 12 .net c# vb.net visual-studio .net-core

我正在为Visual Studio编写调试可视化程序,可视化程序将表达式树呈现为C#或VB.NET伪代码。

我希望默认渲染语言应与当前调试窗口的语言匹配。

另外,我想添加功能以为表达式树中的给定节点生成Watch表达式;这需要知道当前正在调试哪种语言。

如何从可视化工具代码中检测当前正在调试的语言?

(我假设这对于任意运行时代码都是不可能的,因为代码已编译为IL。)

项目发行

Ale*_*lex 9

感谢@dymanoid和@Homer Jay的最终版本是:

public enum SourceLanguage
{
    Unknown, // probably C# for it's the only language without any particular symptom
    VB,
    FSharp,
    Cpp
}

static class Extensions
{
    private static readonly Dictionary<Assembly, SourceLanguage> cache = new Dictionary<Assembly, SourceLanguage>();

    public static SourceLanguage GetSourceLanguage(this Type type) => type.Assembly.GetSourceLanguage();

    public static SourceLanguage GetSourceLanguage(this Assembly assembly)
    {
        if (cache.TryGetValue(assembly, out var sourceLanguage))
            return sourceLanguage;

        var name = assembly.GetName().Name;
        var resources = assembly.GetManifestResourceNames();
        var assemblies = assembly.GetReferencedAssemblies().Select(a => a.Name);
        var types = assembly.DefinedTypes;

        if (assemblies.Contains("Microsoft.VisualBasic") &&
            resources.Contains($"{name}.Resources.resources"))
            sourceLanguage = SourceLanguage.VB;
        else if (assemblies.Contains("FSharp.Core") &&
                 resources.Contains($"FSharpSignatureData.{name}") &&
                 resources.Contains($"FSharpOptimizationData.{name}"))
            sourceLanguage = SourceLanguage.FSharp;
        else if (types.Any(t => t.FullName.Contains("<CppImplementationDetails>.")))
            sourceLanguage = SourceLanguage.Cpp;
        else
            sourceLanguage = SourceLanguage.Unknown;

        cache[assembly] = sourceLanguage;

        return sourceLanguage;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法

如果一个人的类型CSTypeVBTypeFSTypeCppType与创建C#VB.NETF#C++/CLI分别

class Program
{
    static readonly Dictionary<SourceLanguage, string> dict = new Dictionary<SourceLanguage, string>()
    {
        [SourceLanguage.Unknown] = "C#",
        [SourceLanguage.VB] = "VB.NET",
        [SourceLanguage.FSharp] = "F#",
        [SourceLanguage.Cpp] = "C++/CLI"
    };

    static void Main(string[] args)
    {
        Console.WriteLine(string.Format($"Entry assembly source language: {dict[Assembly.GetEntryAssembly().GetSourceLanguage()]}"));
        foreach (var t in new[] { typeof(CSType), typeof(VBType), typeof(FSType), typeof(CppType) })
            Console.WriteLine($"{t.Name} source language: {dict[t.GetSourceLanguage()]}");
    }
}
Run Code Online (Sandbox Code Playgroud)

结果变成

Entry assembly source language: C#
CSType source language: C#
VBType source language: VB.NET
FSType source language: F#
CppType source language: C++/CLI
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请参见编辑。

  • 即使完全有可能从任何源项目中引用每种语言DLL,该nswer可能足以满足我的目的。 (2认同)

dym*_*oid 5

Visual Studio 自定义Visualizer API非常简洁。它没有提供任何方式来获取有关正在调试的代码的其他信息。

确实,您可以按照@Alex提出的方法进行操作。但是,有一些缺点。例如,您可能需要手动加载要调试的程序集(到临时文件夹中AppDomain)。此外,这种方式并不是真正可靠的方法,因为它完全允许C#中实现的Microsoft.VisualBasic程序集引用该程序集。

对于更通用,更安全的方法,可以使用Visual Studio Debugger API

这是一个实现方法:

  • 实现IDebugEventCallback2接口;Visual Studio调试器将使用IDebugEventCallback2.Event方法通知您的代码。
  • 获取一个IVsDebugger实例。
  • 调用IVsDebugger.AdviseDebugEventCallback提供IDebugEventCallback2实现的方法作为事件接收器。
  • 在您的Event方法中,检查IDebugBreakpointEvent2-这是正在调试的进程到达断点的时间;您可能需要使用它QueryInterface进行检查-请参阅“呼叫者注意”
  • 遇到断点时,请使用提供的IDebugThread2实例获取IEnumDebugFrameInfo2对象,请参见IDebugThread2.EnumFrameInfo
  • 调用该IEnumDebugFrameInfo2.Next方法以获取FRAMEINFO结构。
  • 从该结构中,获取一个IDebugStackFrame2实例(m_pFrame字段),并使用其GetLanguageInfo方法获取在当前断点处实现代码的语言。

很长一段时间,是的。但是绝对是(也许是唯一)可靠的。


更新资料

尽管上面引用的Visual Studio Debugger API看起来像本机代码,但是您也可以轻松地在托管代码中使用它。该API基于COM,.NET平台完全支持它。您可以安装Visual Studio SDK,也可以只使用相应的NuGet包,例如Microsoft.VisualStudio.Debugger.Interop。通过添加这些程序包,您可以获得COM类型的托管包装,并且可以在代码中使用它们,就像它们是纯托管C#类型一样。

对于文档,请看一下Visual Studio调试器的可扩展性。您还可以在GitHub上查看Visual Studio SDK示例