UWPアプリケーション(.NET NativeでコンパイルされたC#)からいくつかのクラッシュレポートを読んでいますが、スタックトレースで使用されている正確な構文/形式を理解するのに苦労しています。インターネットでいくつかのガイドを探してみましたが、便利なものは思いつきませんでした。
以下にいくつかの例を示します。
1)
_MyProject.ViewModels.SomeViewModel.<OnLogin>d__69.MoveNext()
_
OnLogin
はSomeViewModel
内のメソッドの名前なので、なぜangular括弧内にあるのですか?_"ClassName".<"MethodName>..."
_が通常の方法でインスタンスメソッド?await
呼び出し間のすべてのコードを匿名メソッドに変換し、継続を使用してそれらをスケジュールすることを理解しているため、_d__69
_は現在のメソッド内の非同期継続を示していると思います。await
呼び出しがないため、これらの番号は連続していないと思います。スタックトレースのその数から元のメソッドの正確な部分を見つけることは可能ですか?MoveNext()
メソッドは何ですか?どのようなタイプが要求されますか?2)
_MyProject.UserControls.SomeControl.<.ctor>b__0_0
_
.ctor
_はオブジェクトコンストラクターを表し、_b__0_0
_はSomeEvent += (s, e) => Foo();
のようにコンストラクター内に追加された匿名イベントハンドラーを表すことがわかりました。 0_1
_、_1_0
_、または何か他にありましたか?3)私はこの方法を持っています:
_// Returns a Task that immediately throws when awaited, as soon as the token is cancelled
public static Task<T> GetWatchedTask<T>(this Task<T> awaitableTask, CancellationToken token)
{
return awaitableTask.ContinueWith(task => task.GetAwaiter().GetResult(), token);
}
_
そして、私はこのスタックトレースを持っています:
_MyProject.Helpers.Extensions.TasksExtensions.<>c__3$1<System.__Canon>.<GetWatchedTask>b__3_0($Task$1<__Canon> task)
_
$Task$1
_が '$'文字で書かれているのはなぜですか?他の場所でも使用できるように、(正規表現のような)プレースホルダー/グラウンドインジケーターのようなものですか? (つまり、_$1<System.__Canon>
_はメソッドの戻り値の型だと思います).<>c__3$1<System.__Canon>
_はどういう意味ですか? _$1
_からは、戻り値の型は_Task<T>
_になると思いますが、非同期呼び出しやイベントハンドラがないため、その_b__3_0
_の部分は何ですか?この場合、それは何か別の意味ですか?4)
_Windows.UI.Xaml.Media.SolidColorBrush..ctor($Color color)
_
5)私はこの他の方法を持っています:
_public static async Task<ObservableCollection<SomeCustomClass>> LoadItemGroups(String parentId)
_
そして、このスタックトレース:
_MyProject.SQLiteDatabase.SQLiteManager.<>c__DisplayClass142_3.<LoadGroups>b__3()
_
c__DisplayClass142_3
_は何ですか?これは、3つの個別のクラス(Task、ObservableCollection、SomeCustomClass)ではなく、単一の型で戻り値の型を示す方法ですか?b__3
_があるのはなぜですか。他のスタックトレースでは、非同期コードチャンクを示すために_d_xxx
_という形式を使用していますか?多くの質問で申し訳ありませんが、この投稿が他のUWP C#プログラマーにも役立つことを願っています。
よろしくお願いします!
[〜#〜] edit [〜#〜]:この質問は重複していると見なされるべきではありませんこの他の質問 の理由:
私は後でエリック・リッペルトが来てより良い答えを出すと思いますが、それが起こらない場合に備えて-私もこれに興味があります。私が得た「d」、「c」、および類似の記号の意味 this エリック・リッパーによる回答。
1)MyProject.ViewModels.SomeViewModel.<OnLogin>d__69.MoveNext()
これは比較的簡単です。 OnLogin
は非同期メソッドであり、そのようなメソッドはコンパイラーによって状態マシンに書き換えられます。このステートマシンは、IAsyncStateMachine
メソッドを持つMoveNext
インターフェイスを実装します。したがって、非同期メソッドは基本的に、その状態マシンのMoveNext
呼び出しのシーケンスになります。そのため、スタックトレースにMoveNext()
が表示されます。
_MyProject.ViewModels.SomeViewModel.<OnLogin>d__69
_は、生成されたステートマシンクラスの名前です。このステートマシンはOnLogin
メソッドに関連しているため、タイプ名の一部になります。 d
は、上記のリンクによる「反復子クラス」です。上記のリンクからの情報は7年前のものであり、async\await実装の前ですが、ステートマシンはイテレータ(同じMoveNext
メソッド、同じ原理)に似ていると思います-したがって、「イテレータクラス」は正常に見えます。 69は、いくつかの一意の数\カウンターです。 2つの非同期メソッドだけでdllをコンパイルすると、それらのステートマシンは_d__0
_および_d__1
_になるため、それは単なるカウンターだと思います。この情報に基づいて、非同期メソッドのどの部分がスローされたかを推測することはできません。
2)b
は「匿名メソッド」です(上記のリンク)。私はいくつかの実験を行いましたが、最初のインデックスは匿名メソッドが使用されたメソッドに関連しており、2番目のインデックスはそれらが使用されたメソッド内の匿名メソッドのインデックスに関連しているようです。たとえば、同じクラスのコンストラクターで2つの匿名メソッドを使用し、メソッドFoo
で2つの匿名メソッドを使用するとします。次に:
_public Test() {
Handler += (s, e) => Foo(); // this will be `b__0_0` because it's first in this method
Handler += (s, e) => Bar(); // this will be `b__0_1` because it's second
}
static void Foo() {
Action a = () => Console.WriteLine("test"); // this is `b__1_0`, 1 refers to it being in another method, not in constructor.
// if we use anonymous method in `Bar()` - it will have this index 2
a();
Action b = () => Console.WriteLine("test2"); // this is `b__1_1`
b();
}
_
3)これはかなり複雑に見えます。まず、「2番目のパラメーター(トークン)が署名に表示されないのはなぜですか」と質問します。これは簡単です。問題のメソッドは、GetWatchedTask
メソッドではなく、匿名メソッドtask => task.GetAwaiter().GetResult()
を表すためです。今、私はこれであなたのスタックトレースを再現できませんでしたが、それでもいくつかの情報があります。まず、_System.__Canon
_は:
一般的なインスタンス化のための「正規」メソッドテーブルをインスタンス化するために使用される内部メソッドテーブル。 「__Canon」という名前はユーザーには決して表示されませんが、ジェネリックを含むデバッガースタックトレースに多く表示されるため、迷惑にならないように意図的に短くします。
私には不可解に見えますが、それは一種のランタイムでのT
を表していると思います。次に、_<>c__3$1<System.__Canon>
_は_<>c__3$1<T>
_であり、コンパイラが生成したクラスの名前です。ここで、「c」は「匿名メソッドクロージャクラス」です(上記のリンクから)。このようなクラスは、クロージャーを作成するときにコンパイラーによって生成されるため、匿名メソッドで外部状態をキャプチャします。キャプチャされたものはどこかに保存されるべきであり、そのようなクラスに保存されます。
さらに、_<GetWatchedTask>b__3_0
_は、上記の匿名クラスのメソッドです。 task => task.GetAwaiter().GetResult()
メソッドを表します。ポイント2のすべてがここでも適用されます。
_$
_の意味がわかりません。たぶん、それは型パラメーターの数を表します。したがって、おそらく_Task$1<System.__Canon>
_は_Task<T>
_を意味し、_Tuple$2<System.__Canon
_のようなものは_Tuple<T1, T2>
_を意味します。
4)残念ながらわかりませんし、再現できませんでした。
5)_c__DisplayClass142_3
_もクロージャクラスです(ポイント3を参照)。 <LoadGroups>b__3()
は、メソッドLoadGroups
で使用した匿名メソッドです。したがって、これは、クロージャー(キャプチャーされた外部状態)であり、LoadGroups
メソッドで呼び出された匿名メソッドを示しています。