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

这个帮助主题解释了为什么会发生这种情况,我认为我理解,但是想知道解决这种行为有哪些选择,特别是在使LINQPad(甚至)功能更强大的背景下.
有趣的是,Visual Studio的调试器能够显示这些对象的属性,甚至是值类型的值:

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方法.
我也遇到了一些同样的问题(除了我正在使用 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 的本质。