6

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

LINQPad 截图

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

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

Visual Studio 调试 ArcObjects

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

ArcObjects .NET SDK包括带有 RCW的PIA,每个 CoClass 可以实现 COM 接口,因此我认为应该可以以编程方式包装这些对象。

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

上一个问题中,我了解到 CoClass 可以在运行时确定,如果它实现IPersist,ArcObjects 的很大一部分就是这样做的。我可以以某种方式使用这种技术或另一种技术来自动System.__ComObject从 PIA 强制 a 到适当的 RCW 吗?如果是这样,我如何在 LINQPad 中实现它,例如通过提供ICustomMemberProvider实现?是否可以将其设为递归,以便同时包装 COM 对象的属性?

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

更新:我已经弄清楚了问题的第一部分,即如何System.__ComObject使用IPersist.GetClassID. 有关我正在使用的代码,请参阅此相关问题此答案。

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

4

1 回答 1

0

我一直有一些相同的问题(除了我正在使用 iTunes COM 库)。

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

我找到的唯一解决方案是,如果我知道列表是什么类型来OfType<>()转换为该类型。这将遍历列表并强制 COM 创建元素。

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

var layers = map.EnumerateLayers("etc")
      .Select(s => s.OfType<Layer>())
      .Dump();

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

var layers = map.EnumerateLayers()
      .OfType<IGeoFeatureLayer>()
      .Dump();

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

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

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

于 2013-02-06T19:27:21.127 回答