为什么获得成员的行为不一致?

当试图在给定的汇编中获得一个类型集合时,我对于解决这个问题的方法感到困惑。从本质上讲,似乎返回结果的方法不会,反之亦然。以下是调试会话即时窗口的输出,其中 appCompilationCompilation (natch)类型。

**appCompilation.GlobalNamespace.GetMembers()**
Count = 14
    [0]: "Namespace Registration"
    [1]: "Namespace Payments"
    [2]: "Namespace Foo"
    [3]: "NamedType "
    [4]: "NamedType "
    [5]: "NamedType "
    [6]: "NamedType "
    [7]: "NamedType "
    [8]: "NamedType "
    [9]: "NamedType "
    [10]: "Namespace Conference"
    [11]: "Namespace System"
    [12]: "NamedType <>f__AnonymousType0<j__TPar>"
    [13]: "Namespace Infrastructure"
**appCompilation.GlobalNamespace.GetTypeMembers()**
{System.Linq.Enumerable.OfTypeIterator}
    source: null
**appCompilation.GlobalNamespace.GetNamespaceMembers()**
{System.Linq.Enumerable.OfTypeIterator}
    source: null

所以我的问题是这样的: 当我在 Kind == Namespace 的Symbol上调用 .GetTypeMembers()时,我得到null。 当我为同一个符号调用 .GetNamespaceMembers()时,我也会得到null。 然而,当我调用 .GetMembers()时,我得到命名空间和类型!

Weirder仍然可以将此语句放入观察窗口并获得非空的非空结果!

appCompilation.GlobalNamespace.GetNamespaceMembers(),结果

可能有关: 启动查询执行似乎并没有发生,但我不确定如何甚至为什么我应该担心这一点......调用 .ToList()有时会触发执行。我曾经想过,即使很多方法提供了 CancellationToken 参数,它们都是同步运行的。一个问题是,各种 GetXXX()方法返回 ReadOnlyArrayIEnumerable ;只读似乎没有像IEnumerable那样从LINQ扩展方法中获取相同的行为。

Judging from a surface scan of debugging output, it looks like GetTypeMembers and its' ilk wrap GetMembers() with an .OfType<> call. Maybe it's in that translation things are getting borked?

无论如何,访问和执行查询的不一致性是非常痛苦的,所以我希望有人能够帮助我理解我错过的东西让事情看起来非常不确定。

编辑:经过一番迭代后,我发现你只需要通过符号树进行递归搜索,并且该查询语法可能比lambda表达式有时更容易... ...哦,是的 - PEBKAC,因为它似乎立即窗口不仅仅是帮助调试工作。

Final Passing查询示例,用于从给定的Compilation中检索所有类型,最多可达三个名称空间的嵌套级别(需要更多测试来涵盖这些情况):

从此(这远比其他一些尝试更好!)

appCompilation.Assembly.GlobalNamespace.GetNamespaceMembers()
    .SelectMany(x => x.GetNamespaceMembers().Select(y => y.GetNamespaceMembers()))
    .SelectMany(x => x, (symbols, symbol) => symbol.GetTypeMembers())
    .SelectMany(x => x);

对于这个(仍然不完全递归,但现在足够好):

from glob in appCompilation.Assembly.GlobalNamespace
    .GetMembers()
    .OfType()
from childNs in glob
    .GetMembers()
    .OfType()
from childTypes in childNs
    .GetTypeMembers()
select childTypes;
0
额外 编辑
意见: 1
在测试失败后,我只在立即窗口中运行该语句,导致我将断点和调试到故障站点:)
额外 作者 Josh E,
FWIW,使用nCrunch修复失败的测试,实际上与使用“立即”窗口相比,其迭代体验并不遥远!
额外 作者 Josh E,
这不就是立即窗口的问题吗?如果您真的尝试使用 foreach 枚举结果,会发生什么?
额外 作者 svick,

1 答案

我认为这只是与Roslyn无关的即时窗口的限制。

例如,使用以下代码:

var ints = new object[] { 2 }.OfType();

我在立即窗口中得到这个输出:

ints
{System.Linq.Enumerable.OfTypeIterator}
    source: null
    System.Collections.Generic.IEnumerator<tresult>.Current: 0
    System.Collections.IEnumerator.Current: 0

但是,如果我使用 foreach 迭代集合,或者在监视窗口中使用Results View,它可以正常工作。

The reason you see what you do is because Enumerable.OfType() is written using an iterator block, which generates the iterator type. The iterator type has some fields with unspeakable names, including <>3__source which holds the original source (the array in my example). It also has one field with a normal name: source, which is set in the call to GetEnumerator(). Since you didn't call that method yet, source is null.

2
额外
有可能我在即时窗口中隐藏了我的原始问题。我会修改我的帖子失败的测试代码
额外 作者 Josh E,
PEBKAC!你是对的 - 即时窗口正在妨碍搞清楚。一旦我简化了我的测试以获得对它们的信任,我就可以迭代到一个解决方案
额外 作者 Josh E,