0

当试图在给定的编译中获取类型的集合时,我对解决问题的方法感到困惑。本质上,似乎返回结果的方法不会,反之亦然。下面是调试会话即时窗口的输出,其中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()的符号时,我得到空值。当我调用相同的符号时,我也会得到空值。然而,当我打电话时,我得到了大量的命名空间和类型!KindNamespace.GetNamespaceMembers().GetMembers()

更奇怪的是,我可以将此语句放入监视窗口并获得非空、非空结果!

appCompilation.GlobalNamespace.GetNamespaceMembers(), results

可能相关:启动查询的执行似乎并没有在我预期的时候发生,但我不完全确定我应该如何甚至为什么我应该担心这个......调用.ToList()有时会触发执行。我原以为,虽然很多方法都提供了CancellationToken参数,但它们都是同步运行的。还有一个问题是各种GetXXX()方法都返回ReadOnlyArrayor IEnumerable; 只读似乎不像 IEnumerable 那样从 LINQ 扩展方法中获得相同的行为。

从调试输出的表面扫描来看,它看起来像GetTypeMembers一个GetMembers()调用.OfType<>。也许是因为翻译变得无聊了?

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

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

从给定编译中检索所有类型的最终传递查询示例,最多三个命名空间嵌套级别左右(需要更多测试来涵盖这些情况):

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

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<NamespaceOrTypeSymbol>()
from childNs in glob
    .GetMembers()
    .OfType<NamespaceSymbol>()
from childTypes in childNs
    .GetTypeMembers()
select childTypes;
4

1 回答 1

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

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

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

于 2012-05-21T19:38:01.430 回答