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()の Symbol を呼び出すと、null になります。同じシンボルを呼び出すと、null も取得されます。それでも、呼び出すと、名前空間と型が豊富に取得されます!KindNamespace.GetNamespaceMembers().GetMembers()

さらに奇妙なことに、このステートメントをウォッチ ウィンドウに配置すると、空でも null でもない結果が得られます。

appCompilation.GlobalNamespace.GetNamespaceMembers(), results

おそらく関連: クエリの実行が期待どおりに開始されないようですが、どのように、またはなぜそれについて心配する必要があるのか​​ さえ正確にはわかりません...呼び出す.ToList()と実行がトリガーされることがあります。多くのメソッドはCancellationTokenパラメーターを提供しますが、それらはすべて同期的に実行されると考えていました。また、さまざまなメソッドがまたはのいずれかGetXXX()を返すという問題もあります。読み取り専用は、IEnumerable と同じ方法で LINQ 拡張メソッドから同じ動作を取得していないようです。ReadOnlyArrayIEnumerable

デバッグ出力の表面スキャンから判断すると、それは次のようGetTypeMembersに見えます。多分それは物事がつまらなくなっているその翻訳にありますか?GetMembers().OfType<>

いずれにせよ、クエリへのアクセスと実行の不一致は非常に苦痛でした。そのため、物事が非常に非決定的であるように見える原因となっている何が欠けているのかを誰かが理解するのを手伝ってくれることを願っています.

EDIT:少し繰り返した後、シンボルツリーを介して再帰的な検索を行うだけでよいことがわかりました。そのクエリ構文は、ラムダ式よりもはるかに簡単なアプローチになる場合があります...そして、そうです-PEBKAC、それ以来イミディエイト ウィンドウは、デバッグ作業を支援する以上に妨げていたようです。

与えられたコンパイルから、3 つの名前空間の入れ子程度までのすべての型を取得する最終的な Passing クエリ サンプル (これらのケースをカバーするには、さらにテストが必要です):

これから (そして、これは他のいくつかの試みよりもはるかに優れています!)

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

ただし、を使用してコレクションを反復するforeachか、ウォッチウィンドウで結果ビューを使用すると、正しく機能します。

Enumerable.OfType()自分が何をしているのかがわかるのは、イテレータタイプを生成するイテレータブロックを使用して記述されているためです。<>3__sourceイテレータタイプには、元のソース(私の例では配列)を保持するものなど、言いようのない名前のフィールドがいくつかあります。また、通常の名前のフィールドが1つあります。sourceこれは、の呼び出しで設定されGetEnumerator()ます。そのメソッドをまだ呼び出していないので、sourceですnull

于 2012-05-21T19:38:01.430 に答える