为什么让成员表现不一致?

时间:2012-05-21 17:35:56

标签: c#-4.0 roslyn

在尝试获取给定编译中的类型集合时,我对于解决问题的方法感到困惑。基本上,似乎返回结果的方法不会,反之亦然。下面是调试会话立即窗口的输出,其中appCompilation的类型为Compilation(natch)。

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

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

Weirder仍然,我可以将此语句放入监视窗口并获得非空的非空结果!

appCompilation.GlobalNamespace.GetNamespaceMembers(), results

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

从调试输出的表面扫描判断,它看起来像GetTypeMembers及其“GetMembers() .OfType<>调用appCompilation.Assembly.GlobalNamespace.GetNamespaceMembers() .SelectMany(x => x.GetNamespaceMembers().Select(y => y.GetNamespaceMembers())) .SelectMany(x => x, (symbols, symbol) => symbol.GetTypeMembers()) .SelectMany(x => x); 。也许是因为翻译事情变得越来越糟糕了?

无论如何,访问和执行查询的不一致都非常痛苦,所以我希望有人可以帮助我理解我所缺少的东西,这使得事情看起来非常不确定。

编辑:在稍微迭代之后,我发现你只需要通过符号树进行递归搜索,而且查询语法可能比lambda表达式更容易...而且是的 - 是的 - PEBKAC因为看起来立即窗口不仅仅是帮助调试工作。

Final Passing查询示例,它从给定的编译中检索所有类型,最多达到三个命名空间嵌套的级别(需要更多测试来覆盖这些情况):

从此(这比其他一些尝试要好得多!)

from glob in appCompilation.Assembly.GlobalNamespace
    .GetMembers()
    .OfType<NamespaceOrTypeSymbol>()
from childNs in glob
    .GetMembers()
    .OfType<NamespaceSymbol>()
from childTypes in childNs
    .GetTypeMembers()
select childTypes;

对此(仍然不完全递归,但现在已经足够好了):

{{1}}

1 个答案:

答案 0 :(得分:2)

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

例如,使用以下代码:

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

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

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

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

您看到自己所做的是因为Enumerable.OfType()是使用迭代器块编写的,它生成迭代器类型。迭代器类型有一些字段具有不可描述的名称,包括<>3__source保存原始源(我的示例中的数组)。它还有一个具有正常名称的字段:source,在GetEnumerator()的调用中设置。由于您尚未调用该方法,sourcenull