应用没有程序集依赖项的调试器可视化工具
Apply a debugger visualizer without assembly dependencies
我正在尝试创建适用于各种对象的调试可视化工具
没有使可视化程序集成为依赖项。我想将此可视化工具应用于各种 classes,包括私有嵌套、内部以及涉及大量复杂泛型(父级和嵌套 classes)。这意味着我正在创建一个仅包含关键数据的代理对象。
我不希望我的主程序集依赖于可视化程序集,也不希望可视化程序集知道主程序集的内容。
在主程序集中,我有这样的东西:
namespace MainAsm
{
public interface IVisualizable
{
DebugProxy DebugVisualizer { get; }
}
[Serializable]
public class DebugProxy
{
// data required for visualization here
public DebugProxy() { }
public DebugProxy(IVisualizable source)
{
var orig = source.DebugVisualizer;
// copy properties from orig
}
}
}
然后对于可视化工具,我的代码如下所示:
[assembly:System.Diagnostics.DebuggerVisualizer(
typeof(dbg.Visualizer),
typeof(Microsoft.VisualStudio.DebuggerVisualizers.VisualizerObjectSource),
TargetTypeName="MainAsm.DebugProxy, MainAsm",
Description="MainAsm Debug Visualizer")]
namespace dbg
{
public class Visualizer : Microsoft.VisualStudio.DebuggerVisualizers.DialogDebuggerVisualizer
{
protected override void Show(
Microsoft.VisualStudio.DebuggerVisualizers.IDialogVisualizerService windowService,
Microsoft.VisualStudio.DebuggerVisualizers.IVisualizerObjectProvider objectProvider)
{
object data = objectProvider.GetObject();
if (data == null)
return;
var t = data.GetType();
var prop = t.GetProperty("DebugVisualizer");
if (prop != null)
{
data = prop.GetValue(data, null) ?? data;
}
// use reflection to grab additional properties and open a window
}
}
}
我希望能够将可视化工具应用于任何知道如何创建 DebugProxy 的 class。如果我展开一个对象并单击它的 DebugVisualizer 属性,我显然可以获得一个可视化工具,但我希望可视化与顶级对象相关联。所以如果我有这样的东西:
[System.Diagnostics.DebuggerVisualizer(???)]
public class MyClass<TThis, T2, T3> : IVisualizable
where TThis : MyClass<TThis, T2, T3>, new()
where T2 : SomeOtherClass2<T2, T3>, new()
where T3 : SomeOtherClass3<T2, T3>, new()
{
DebugProxy IVisualizable.DebugVisualizer { get { return CreateProxy(); } }
}
问题是,我需要用什么来代替 ???让它将可视化工具与 MyClass<,> 及其后代相关联?
--
- 如果我输入 [System.Diagnostics.DebuggerTypeProxy(typeof(DebugProxy))] DebugProxy 不会显示可视化工具图标
- 如果我输入 [System.Diagnostics.DebuggerVisualizer("dbg.Visualizer")],我会在 [=] 得到一个 NullReferenceException 62=]
- 如果我输入 [System.Diagnostics.DebuggerVisualizer("dbg.Visualizer, dbg")],我得到“无法加载文件或程序集 dbg 或一个它的依赖项”,即使日志在尝试解析程序集时在 "Initial PrivatePath = " 下显示了正确的路径。
- 如果我输入 [System.Diagnostics.DebuggerVisualizer("dbg.Visualizer", "Microsoft.VisualStudio.DebuggerVisualizers.VisualizerObjectSource")],我会得到“无法创建可视化工具Object Source.”调用栈是DebuggerVisualizeres.DebugViewerShim命名空间中的一系列方法:"DelegatedHost.CreateViewer" -> "PrivateCallback.MaybeDeserializeAndthrowException" -> "DebugeeHost.CreateSourceInternal" -> "RemoteObjectSourceException"
秘诀是创建自定义的 VisualizerObjectSource 并将其放入 GAC:
namespace dbg
{
public class CustomObjectSource
: Microsoft.VisualStudio.DebuggerVisualizers.VisualizerObjectSource
{
private static object ConvertObject(object oldObj)
{
if (oldObj == null)
return null;
foreach (var intf in oldObj.GetType().GetInterfaces())
{
var prop = intf.GetProperty("DebugVisualizer");
if (prop != null)
return prop.GetValue(oldObj, null);
}
return oldObj;
}
public override void TransferData(object target, Stream incomingData, Stream outgoingData)
{
base.TransferData(ConvertObject(target), incomingData, outgoingData);
}
public override object CreateReplacementObject(object target, Stream incomingData)
{
return ConvertObject(base.CreateReplacementObject(ConvertObject(target), incomingData));
}
public override void GetData(object target, Stream outgoingData)
{
base.GetData(ConvertObject(target), outgoingData);
}
}
}
然后将以下属性放在实现 IVisualizable 的 classes 上:
[System.Diagnostics.DebuggerVisualizer(
"dbg.Visualizer, dbg, Version=1.0.0.0, Culture=neutral, PublicKeyToken=???",
"dbg.CustomObjectSource, dbg, Version=1.0.0.0, Culture=neutral, PublicKeyToken=???"]
在哪里???是程序集的 public 键。
带有 CustomObjectSource 的程序集进入 GAC 非常重要,因为这可以确保无论其基本路径设置为什么,它都可以加载到被调试应用程序域中。确保它有一个强名称并在 Visual Studio 命令提示符下使用 "gacutil /f /i dbg.dll" 来安装它。
然后当您尝试可视化您的 class 时,它会将 CustomObjectSource 加载到您的应用程序域中,使用 CreateReplacementObject 方法将其转换为可序列化类型,并在 DebugProxy 对象而不是原始类型.
我正在尝试创建适用于各种对象的调试可视化工具 没有使可视化程序集成为依赖项。我想将此可视化工具应用于各种 classes,包括私有嵌套、内部以及涉及大量复杂泛型(父级和嵌套 classes)。这意味着我正在创建一个仅包含关键数据的代理对象。
我不希望我的主程序集依赖于可视化程序集,也不希望可视化程序集知道主程序集的内容。
在主程序集中,我有这样的东西:
namespace MainAsm
{
public interface IVisualizable
{
DebugProxy DebugVisualizer { get; }
}
[Serializable]
public class DebugProxy
{
// data required for visualization here
public DebugProxy() { }
public DebugProxy(IVisualizable source)
{
var orig = source.DebugVisualizer;
// copy properties from orig
}
}
}
然后对于可视化工具,我的代码如下所示:
[assembly:System.Diagnostics.DebuggerVisualizer(
typeof(dbg.Visualizer),
typeof(Microsoft.VisualStudio.DebuggerVisualizers.VisualizerObjectSource),
TargetTypeName="MainAsm.DebugProxy, MainAsm",
Description="MainAsm Debug Visualizer")]
namespace dbg
{
public class Visualizer : Microsoft.VisualStudio.DebuggerVisualizers.DialogDebuggerVisualizer
{
protected override void Show(
Microsoft.VisualStudio.DebuggerVisualizers.IDialogVisualizerService windowService,
Microsoft.VisualStudio.DebuggerVisualizers.IVisualizerObjectProvider objectProvider)
{
object data = objectProvider.GetObject();
if (data == null)
return;
var t = data.GetType();
var prop = t.GetProperty("DebugVisualizer");
if (prop != null)
{
data = prop.GetValue(data, null) ?? data;
}
// use reflection to grab additional properties and open a window
}
}
}
我希望能够将可视化工具应用于任何知道如何创建 DebugProxy 的 class。如果我展开一个对象并单击它的 DebugVisualizer 属性,我显然可以获得一个可视化工具,但我希望可视化与顶级对象相关联。所以如果我有这样的东西:
[System.Diagnostics.DebuggerVisualizer(???)]
public class MyClass<TThis, T2, T3> : IVisualizable
where TThis : MyClass<TThis, T2, T3>, new()
where T2 : SomeOtherClass2<T2, T3>, new()
where T3 : SomeOtherClass3<T2, T3>, new()
{
DebugProxy IVisualizable.DebugVisualizer { get { return CreateProxy(); } }
}
问题是,我需要用什么来代替 ???让它将可视化工具与 MyClass<,> 及其后代相关联?
--
- 如果我输入 [System.Diagnostics.DebuggerTypeProxy(typeof(DebugProxy))] DebugProxy 不会显示可视化工具图标
- 如果我输入 [System.Diagnostics.DebuggerVisualizer("dbg.Visualizer")],我会在 [=] 得到一个 NullReferenceException 62=]
- 如果我输入 [System.Diagnostics.DebuggerVisualizer("dbg.Visualizer, dbg")],我得到“无法加载文件或程序集 dbg 或一个它的依赖项”,即使日志在尝试解析程序集时在 "Initial PrivatePath = " 下显示了正确的路径。
- 如果我输入 [System.Diagnostics.DebuggerVisualizer("dbg.Visualizer", "Microsoft.VisualStudio.DebuggerVisualizers.VisualizerObjectSource")],我会得到“无法创建可视化工具Object Source.”调用栈是DebuggerVisualizeres.DebugViewerShim命名空间中的一系列方法:"DelegatedHost.CreateViewer" -> "PrivateCallback.MaybeDeserializeAndthrowException" -> "DebugeeHost.CreateSourceInternal" -> "RemoteObjectSourceException"
秘诀是创建自定义的 VisualizerObjectSource 并将其放入 GAC:
namespace dbg
{
public class CustomObjectSource
: Microsoft.VisualStudio.DebuggerVisualizers.VisualizerObjectSource
{
private static object ConvertObject(object oldObj)
{
if (oldObj == null)
return null;
foreach (var intf in oldObj.GetType().GetInterfaces())
{
var prop = intf.GetProperty("DebugVisualizer");
if (prop != null)
return prop.GetValue(oldObj, null);
}
return oldObj;
}
public override void TransferData(object target, Stream incomingData, Stream outgoingData)
{
base.TransferData(ConvertObject(target), incomingData, outgoingData);
}
public override object CreateReplacementObject(object target, Stream incomingData)
{
return ConvertObject(base.CreateReplacementObject(ConvertObject(target), incomingData));
}
public override void GetData(object target, Stream outgoingData)
{
base.GetData(ConvertObject(target), outgoingData);
}
}
}
然后将以下属性放在实现 IVisualizable 的 classes 上:
[System.Diagnostics.DebuggerVisualizer(
"dbg.Visualizer, dbg, Version=1.0.0.0, Culture=neutral, PublicKeyToken=???",
"dbg.CustomObjectSource, dbg, Version=1.0.0.0, Culture=neutral, PublicKeyToken=???"]
在哪里???是程序集的 public 键。
带有 CustomObjectSource 的程序集进入 GAC 非常重要,因为这可以确保无论其基本路径设置为什么,它都可以加载到被调试应用程序域中。确保它有一个强名称并在 Visual Studio 命令提示符下使用 "gacutil /f /i dbg.dll" 来安装它。
然后当您尝试可视化您的 class 时,它会将 CustomObjectSource 加载到您的应用程序域中,使用 CreateReplacementObject 方法将其转换为可序列化类型,并在 DebugProxy 对象而不是原始类型.