且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何获得LINQPad到Dump()System .__ ComObject引用?

更新时间:2022-12-04 21:12:56

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



在visual studio中你并没有意识到,但是每个调试窗口都要求COM库在打开它时创建类型。这是不同于Dump(),这是,很好,不是互动。



我发现的唯一解决方案是,如果我知道什么类型的列表是做一个 OfType<>()强制转换为该类型。这将迭代列表并强制COM创建元素。



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

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

NB - 您的毫米可能会有所不同, >

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

根据COM你可能需要把这个到下一步,并从那里拉出成员(使用com你必须要求得到的值)这样:

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

当然,如果有一个神奇的方式来做到这一点, t相信有因为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.