我正在编写一个debugging visualizer for Visual Studio,它将表达式树呈现为C#或VB.NET伪代码。
我希望默认渲染语言应与当前调试窗口的语言匹配。
此外,我想添加功能来为表达式树中的给定节点生成Watch表达式;这需要知道当前正在调试哪种语言。
如何从可视化工具代码中检测当前正在调试哪种语言?
(我假设从任意运行时代码中都不可能做到这一点,因为代码已编译为IL。)
答案 0 :(得分:8)
感谢@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;
}
}
用法:
如果一个人的类型为CSType
,VBType
,FSType
和CppType
,C#
,VB.NET
和F#
分别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()]}");
}
}
结果
Entry assembly source language: C#
CSType source language: C#
VBType source language: VB.NET
FSType source language: F#
CppType source language: C++/CLI
有关详细信息,请参见编辑。
答案 1 :(得分:6)
Visual Studio Custom Visualizer API非常简洁。它没有提供任何方式来获取有关正在调试的代码的其他信息。
实际上,您可以按照@Alex提出的方法进行操作。但是,有一些缺点。例如。您可能需要手动将要调试的程序集加载到临时AppDomain
中。此外,这种方法并不是真正可靠的方法,因为它完全允许C#中实现的程序集引用Microsoft.VisualBasic
程序集。
对于更通用,更安全的方法,您可以使用Visual Studio Debugger API。
这里是一个实现方法的想法:
IDebugEventCallback2
界面; Visual Studio调试器将使用IDebugEventCallback2.Event
方法通知您的代码。IVsDebugger
实例。IVsDebugger.AdviseDebugEventCallback
方法,将您的IDebugEventCallback2
实现作为事件接收器。Event
方法中,检查IDebugBreakpointEvent2
-这是要调试的进程到达断点的时间;您可能需要使用QueryInterface
进行检查-请参见Note for Callers。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 debugger extensibility。您还可以在GitHub上检出Visual Studio SDK samples。
答案 2 :(得分:2)
应该考虑到还有另一种可能性。该程序集可以用C ++ / CLI编写。
但这很有趣。它在清单中说明。 C ++ / CLI清单中的所有其他内容都与C#版本相同。
// Metadata version: v4.0.30319 (C++/CLI)
.assembly extern mscorlib
{
...
}
...