问题描述
我正在使用 解释了为什么会发生这种情况,我想我理解,但想知道有哪些选项可以解决此问题,尤其是在使 LINQPad(甚至)更强大的情况下.
有趣的是,Visual Studio 的调试器能够显示这些对象的属性,甚至是值类型的值:
Visual Studio 使用什么机制来实现这种自省,为什么 LINQPad 的 Dump 方法不做同样的事情?请参阅有关 VS 如何执行此操作的相关问题:Visual Studio 的调试器/交互式窗口如何转储.NET 中的 COM 对象?
ArcObjects .NET SDK 包括带有 RCW 的 PIA对于每个 CoClass,可以实现一个 COM 接口,所以我认为应该可以以编程方式包装这些对象.
作为一种解决方法,我已成功使用 Marshal.CreateWrapperOfType()
在我的 LINQ 查询中强制 LINQPad 在我碰巧知道应该使用哪个 CoClass 时转储对象的属性.当然,这只会正确地转储值类型属性——任何基于 COM 的引用类型属性仍报告为 System.__ComObject
,因此正确的解决方案必须递归地工作以将这些属性包装起来.
在 previous question 中,我了解到 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 的解决方案,但这不是必需的).
更新:我已经弄清楚了我的问题的第一部分,即如何使用 返回的 CLSID 在其 RCW 中包装
.请参阅此相关问题和此回答我正在使用的代码.System.__ComObject
IPersist.GetClassID
我仍然想知道如何将其用于 LINQPad 的 Dump 方法.
我遇到了一些相同的问题(除了我正在使用 iTunes COM 库).
在 Visual Studio 中,您没有意识到这一点,但每个调试窗口都要求 COM 库在您打开它时创建类型.这与 Dump() 不同,后者不是交互式的.
我找到的唯一解决方案是,如果我知道列表是什么类型,则将 OfType<>()
强制转换为该类型.这将遍历列表并强制 COM 创建元素.
所以在你上面的例子中你会说:
var layers = map.EnumerateLayers("etc").Select(s => s.OfType()).倾倒();
注意 - 您的数量可能会有所不同,事实证明对于 OP 示例来说这是必需的.
var layers = map.EnumerateLayers().OfType().倾倒();
根据 COM,您可能需要将其带到下一步并从那里提取成员(对于 com,您必须要求获取值)如下所示:
var layers = map.EnumerateLayers("etc").Select(x => x.OfType<层>()).Select(x => new { x.Depth, x.Dimention, })//等等.倾倒();
如果有一种神奇"的方式来实现这一点当然会很好,但我不相信这是因为 COM 的性质.
I am playing around with using LINQPad to rapidly develop small ArcObjects (a COM-based library for ESRI's ArcGIS software) applications and have had some success in using it to Dump()
the properties of COM objects that I initialize from .NET, but any COM objects that are obtained from an existing COM object are simply dumped as System.__ComObject
references, which is not particularly useful:
This help topic explains why this is happening, which I think I understand, but would like to know what options there are for working around this behavior, especially in the context of making LINQPad (even) more powerful.
Interestingly, Visual Studio's debugger is able to display the properties of these objects, and even values for value types:
What mechanism does Visual Studio use to achieve this introspection, and why doesn't LINQPad's Dump method do the same? Edit: See related question about how VS does this: How does Visual Studio's debugger/interactive window dump the properties of COM Objects in .NET?
The ArcObjects .NET SDK includes PIAs with RCWs for each CoClass a COM interface may be implemented by, so I'm thinking it should be possible to wrap these objects programmatically.
As a workaround I have successfully used Marshal.CreateWrapperOfType()
within my LINQ queries to coerce LINQPad to dump the properties of the object when I happen to know which CoClass should be used. Of course, this only properly dumps value type properties -- any COM-based reference type properties are still reported as System.__ComObject
, so a proper solution would have to work recursively to get those wrapped as well.
In a previous question I learned that the CoClass can be determined at runtime if it implements IPersist
, which a good portion of ArcObjects do. Can I somehow use this technique, or another one, to automatically coerce a System.__ComObject
to the appropriate RCW from the PIAs? And if so, how can I implement this in LINQPad, e.g. by providing an ICustomMemberProvider
implementation? Can this be made to be recursive, so that properties that are also COM objects be wrapped as well?
I am using LINQPad 4.x which targets .NET 4.0, but am also interested in supporting LINQPad 2.x (so solutions that work on both .NET 3.5 and .NET 4.0 would be preferred, but that's not a requirement).
Update: I've figured out the first part of my question which was how to wrap a System.__ComObject
in its RCW using the CLSID returned by IPersist.GetClassID
. See this related question and this answer for the code I'm using.
I would still like to know how I can work this into LINQPad's Dump method.
I've been having some of the same issues (except I'm working with iTunes COM library).
In visual studio you don't realize it but each debug window is asking the COM library to create the type when you open it. This is different than Dump() which is, well, not interactive.
The only solution I've found is if I know what type the list is to do a OfType<>()
cast to that type. This will iterate over the list and force COM to create the elements.
So in your example above you would say:
var layers = map.EnumerateLayers("etc")
.Select(s => s.OfType<Layer>())
.Dump();
NB - Your millage may vary, it turns out for the OP example this was needed.
var layers = map.EnumerateLayers()
.OfType<IGeoFeatureLayer>()
.Dump();
Depending on the COM you might have to take this to the next step and pull out the members from there (with com you have to ask to get the value) something like this:
var layers = map.EnumerateLayers("etc")
.Select(x => x.OfType<Layer>())
.Select(x => new { x.Depth, x.Dimention, }) // etc
.Dump();
Sure would be nice if there was a "magical" way to make this happen, but I don't believe there is because of the nature of COM.
这篇关于如何让 LINQPad 转储() System.__ComObject 引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!