如何让LINQPad转到Dump()系统.__ ComObject引用?

bla*_*238 5 c# com com-interop rcw linqpad

我正在使用LINQPad快速开发小型ArcObjects(一个基于COM的ESRI ArcGIS软件库)应用程序,并且已经成功地将它用于Dump()我从.NET初始化的COM对象的属性,但任何COM对象从现有COM对象获得的只是作为System.__ComObject引用转储,这不是特别有用:

LINQPad截图

这个帮助主题解释了为什么会发生这种情况,我认为我理解,但是想知道解决这种行为有哪些选择,特别是在使LINQPad(甚至)功能更强大的背景下.

有趣的是,Visual Studio的调试器能够显示这些对象的属性,甚至是值类型的值:

Visual Studio调试ArcObjects

Visual Studio使用什么机制来实现这种内省,为什么LINQPad的Dump方法不会这样做呢?编辑:请参阅有关VS如何执行此操作的相关问题:Visual Studio的调试器/交互式窗口如何在.NET中转储COM对象的属性?

ArcObjects的.NET SDK包括具有的RCW每个伴生类的COM接口可以通过实施PIA的,所以我想应该可以以编程方式包装这些对象.

作为一种解决方法,我成功地Marshal.CreateWrapperOfType()在我的LINQ查询中使用来强制LINQPad在我碰巧知道应该使用哪个CoClass时转储对象的属性.当然,这只能正确转储值类型属性 - 任何基于COM的引用类型属性仍然被报告为System.__ComObject,因此正确的解决方案必须以递归方式工作以获取包装.

之前的一个问题中,我了解到CoClass可以在运行时确定它是否实现IPersist,而ArcObjects的很大一部分都是如此.我可以以某种方式使用这种技术或其他技术自动强制System.__ComObject从PIA到适当的RCW吗?如果是这样,我如何在LINQPad中实现它,例如通过提供ICustomMemberProvider实现?这可以是递归的,因此也可以包装也是COM对象的属性吗?

我正在使用针对.NET 4.0的LINQPad 4.x,但我也对支持LINQPad 2.x感兴趣(因此,首选适用于.NET 3.5和.NET 4.0的解决方案,但这不是必需的).

更新:我已经弄清楚我的问题的第一部分是如何System.__ComObject使用返回的CLSID在其RCW中包装IPersist.GetClassID.请参阅此相关问题和我正在使用的代码的答案.

我仍然想知道如何将其用于LINQPad的Dump方法.

Hog*_*gan 0

我也遇到了一些同样的问题(除了我正在使用 iTunes COM 库)。

在 Visual Studio 中,您没有意识到这一点,但每个调试窗口在您打开它时都会要求 COM 库创建类型。这与 Dump() 不同,后者不是交互式的。

我找到的唯一解决方案是,如果我知道列表是什么类型,则可以OfType<>()对该类型进行强制转换。这将迭代列表并强制 COM 创建元素。

所以在上面的例子中你会说:

var layers = map.EnumerateLayers("etc")
      .Select(s => s.OfType<Layer>())
      .Dump();
Run Code Online (Sandbox Code Playgroud)

注意 - 你的里程数可能会有所不同,事实证明对于 OP 示例来说这是需要的。

var layers = map.EnumerateLayers()
      .OfType<IGeoFeatureLayer>()
      .Dump();
Run Code Online (Sandbox Code Playgroud)

根据 COM,您可能必须将其带到下一步并从那里提取成员(对于 com,您必须要求获取值),如下所示:

var layers = map.EnumerateLayers("etc")
      .Select(x => x.OfType<Layer>())
      .Select(x => new { x.Depth, x.Dimention, }) // etc 
      .Dump();
Run Code Online (Sandbox Code Playgroud)

如果有一种“神奇”的方式来实现这一点当然会很好,但我不相信这是因为 COM 的本质。