【发布时间】:2013-01-20 22:20:50
【问题描述】:
我正在尝试使用LINQPad 快速开发小型ArcObjects(ESRI's ArcGIS 软件的基于 COM 的库)应用程序,并且在使用它到 Dump() 的 COM 对象的属性方面取得了一些成功我从 .NET 初始化,但是从现有 COM 对象获得的任何 COM 对象都被简单地转储为 System.__ComObject 引用,这并不是特别有用:
This help topic 解释了为什么会发生这种情况,我想我理解这一点,但想知道有哪些选项可以解决此问题,尤其是在使 LINQPad(甚至)更强大的情况下。
有趣的是,Visual Studio 的调试器能够显示这些对象的属性,甚至是值类型的值:
Visual Studio 使用什么机制来实现这种自省,为什么 LINQPad 的 Dump 方法不做同样的事情? 编辑:请参阅有关 VS 如何做到这一点的相关问题:How does Visual Studio's debugger/interactive window dump the properties of COM Objects in .NET?
ArcObjects .NET SDK 包括带有 RCW 的 PIA,每个 CoClass 可以实现 COM 接口,因此我认为应该可以通过编程方式包装这些对象。
作为一种解决方法,当我碰巧知道应该使用哪个 CoClass 时,我已在我的 LINQ 查询中成功使用Marshal.CreateWrapperOfType() 来强制 LINQPad 转储对象的属性。当然,这只会正确转储值类型属性——任何基于 COM 的引用类型属性仍报告为System.__ComObject,因此正确的解决方案必须递归地工作以将这些属性也包装起来。
在previous question 中,我了解到如果 CoClass 实现了 IPersist,则可以在运行时确定 CoClass,ArcObjects 的很大一部分都是这样做的。我可以以某种方式使用这种技术或另一种技术来自动将System.__ComObject 从 PIA 强制转换为适当的 RCW 吗?如果是这样,我如何在 LINQPad 中实现它,例如通过提供ICustomMemberProvider 实现?是否可以将其设为递归,以便同时包装 COM 对象的属性?
我正在使用面向 .NET 4.0 的 LINQPad 4.x,但我也对支持 LINQPad 2.x 感兴趣(因此首选适用于 .NET 3.5 和 .NET 4.0 的解决方案,但这不是必需的) .
更新:我已经弄清楚了我的问题的第一部分,即如何使用 IPersist.GetClassID 返回的 CLSID 在其 RCW 中包装 System.__ComObject。请参阅此 related question 和 this answer 了解我正在使用的代码。
我仍然想知道如何将其用于 LINQPad 的 Dump 方法。
【问题讨论】:
-
我不知道 Visual Studio 是如何做到这一点的。如果你能弄清楚这一点,我可以让 LINQPad 做同样的事情。
-
谢谢乔,如果可以的话,那就太好了!我只能推测,但根据我有限的理解,它有两种基本的工作方式:1)反映支持接口的主互操作程序集和 2)使用
IDispatch。由于我正在使用的所有对象都没有实现IDispatch,所以它必须是前者,至少对于调试视图的正常部分。我相信 VS2010 的“动态”视图使用IDispatch。但是,对于我的对象,动态视图只会显示“无法发现有关此对象的更多信息”。 -
在linked answer 中,我实际上比这两种方法更进一步,将 COM 对象显式包装在相应的 Runtime Callable Wrapper 中,从而产生最详细的输出(因为它包括成员来自所有实现的接口),但这依赖于实现
IPersist的对象,这绝对不是通用的。您能否建议为我的 RCW 转换方法提供ICustomMemberProvider是否可行? -
是的,如果您实现 ICustomMemberProvider,您可以让 LINQPad 显示您喜欢的任何内容。虽然如果我能让 LINQPad 像 VS 一样自动处理所有 COM 对象会更好。
-
你不能为所有 System.__ComObjects 实现接口。仅适用于特定类型。
标签: c# com com-interop linqpad rcw