How to read / interpret the original C # stack trace?

I read some crash reports from a UWP application (C # compiled with .NET Native), and I hardly understand the exact syntax / format used in the stack trace. I tried looking for some guides on the Internet, but I did not come up with anything useful.

Here are some examples:

one)

MyProject.ViewModels.SomeViewModel.<OnLogin>d__69.MoveNext() 
  • OnLogin is the method name in SomeViewModel , so why is it inside angular brackets? Is "ClassName".<"MethodName>..." usual way to specify an instance method?
  • I understand that the C # compiler turns each piece of code between await calls into anonymous methods and schedules them using continuations, so I think d__69 indicates an async continuation inside the current method.
    • What does "d" mean?
    • Are these numbers random? I mean, the method does not have 69 await calls, so I think these numbers are not sequential. Is it possible to find out the exact part of the original method from this number in the stack trace?
  • What is this MoveNext() method at the end? What type is he called to?

2)

 MyProject.UserControls.SomeControl.<.ctor>b__0_0 
  • I know that .ctor denotes the constructor of an object, and looking at the code, I found that b__0_0 means an anonymous event handler added inside the constructor, for example: SomeEvent += (s, e) => Foo(); .
    • What does b mean?
    • Why are there two underscored numbers? Which one relates to the anonymous method? I mean, it's the first one (so its index is 0), but there are two 0. If it were the second, would I have 0_1 , 1_0 or something else?

3) I have this method:

 // 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); } 

And I have a stack trace:

 MyProject.Helpers.Extensions.TasksExtensions.<>c__3$1<System.__Canon>.<GetWatchedTask>b__3_0($Task$1<__Canon> task) 
  • Why does the second parameter (token) not appear in the signature?
  • Why is the type $Task$1 written with the character '$'? Is it like some kind of indicator of a place / land (as in regular expression) so that it can be used in other places? (I mean, I see that $1<System.__Canon> in what I think is the return type of the method)
    • If this first part is the return type of the method, why doesn't it exist for all methods that have a return type? I have many stack traces with a method returning a value, but they do not have the same signature.
  • What does all this mean .<>c__3$1<System.__Canon> ? From $1 and, I think, it will be a return type of type Task<T> , but what part is b__3_0 , since I have no asynchronous calls or event handlers? Does this mean something else in this case?

4)

 Windows.UI.Xaml.Media.SolidColorBrush..ctor($Color color) 
  • Why does the parameter type begin with the character '$'? What does it mean?

5) I have another method:

 public static async Task<ObservableCollection<SomeCustomClass>> LoadItemGroups(String parentId) 

And this stack trace:

 MyProject.SQLiteDatabase.SQLiteManager.<>c__DisplayClass142_3.<LoadGroups>b__3() 
  • What is c__DisplayClass142_3 ? Is this a way to specify the return type of a single type and not three separate classes (Task, ObservableCollection, SomeCustomClass)?
  • Again, why do I have b__3 here, where other stack traces use the d_xxx format to indicate a piece of asynchronous code?

Sorry for the many questions, I hope this post helps other CW C # programmers.

Thank you in advance for your help!

EDIT : This question should not be considered a duplicate of other questions because:

  • Different cases are presented here (design methods, syntax of common types, etc.) instead of just setting the default value of some keywords / characters related to a particular type of variable
  • It specifically asks how to compare a given stack trace with the original method signature and the steps that must be taken to achieve this.
  • He presents different examples in different contexts, and not just asks a general question.
  • And by the way, how can you call the "names of the VS debugger magicians" even the right question? How should another user have to find this question when searching for trace characters of a C # stack?
+7
c # visual-studio uwp .net-native
source share
1 answer

I am sure that Eric Lippert will come later and give a better answer, but in case this does not happen - here is my trick, because I was also interested in this. The meaning of "d", "c" and similar characters I received from this answer by Eric Lippert.

1) MyProject.ViewModels.SomeViewModel.<OnLogin>d__69.MoveNext()

It is relatively simple. OnLogin is an asynchronous method, and such methods are overwritten by the compiler in the state machine. This state machine implements the IAsyncStateMachine interface, which has a IAsyncStateMachine method. Thus, your async method basically becomes a sequence of MoveNext calls to this state machine. This is why you see MoveNext() in the stack trace.

MyProject.ViewModels.SomeViewModel.<OnLogin>d__69 is the name of the generated state machine class. Since this state machine is associated with the OnLogin method, it becomes part of the type name. d is the "iterator class" from the link above. Please note that the information from the link above is 7 years old and is in front of the async \ await implementation, but I assume that the state machine is like an iterator (same MoveNext method, same principle) - so the iterator class looks fine. 69 is a unique counter number. I think this is just a counter, because if I compile the dll with two asynchronous methods, their state machines will be d__0 and d__1 . It is not possible to deduce that part of the asynchronous method that was selected based on this information.

2) b is an โ€œanonymous methodโ€ (link above). I did some experiments, and I think that the first index is associated with the method in which the anonymous method was used, and the second index is associated with the index of the anonymous method inside the method in which they are used. For example, suppose you use 2 anonymous methods in a constructor and 2 anonymous methods in a Foo method in the same class. Then:

 public Test() { Handler += (s, e) => Foo(); // this will be `b__0_0` because it first in this method Handler += (s, e) => Bar(); // this will be `b__0_1` because it 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) It looks rather complicated. First you ask: "Why is the second parameter (token) not displayed in the signature." This is simple - because the method in question is an anonymous task => task.GetAwaiter().GetResult() method, not your GetWatchedTask method. Now I could not reproduce the stack trace from this, but still some information. First, System.__Canon :

The internal method table used to instantiate the "canonical" method for standard instances. The name "__Canon" will never be visible to users, but it will be displayed a lot in the debugger stack trace using generics, so it is kept intentionally short to avoid troubles.

It looks mysterious to me, but I assume that it represents your T at runtime. Then <>c__3$1<System.__Canon> is <>c__3$1<T> and is the name of the class generated by the compiler, where "c" is the "anonymous method closure class" (from the link above). Such a class is generated by the compiler when creating a closure, so fix some external state in your anonymous method. What was captured must be stored somewhere, and it is stored in that class.

Next, <GetWatchedTask>b__3_0 is the method in the anonymous class above. It represents your method task => task.GetAwaiter().GetResult() . Everything from point 2 also applies here.

I do not know the value of $ , perhaps it represents the number of type parameters. Therefore, perhaps Task$1<System.__Canon> means Task<T> , and something like Tuple$2<System.__Canon will mean Tuple<T1, T2> .

4) What I, unfortunately, do not know and could not reproduce.

5) c__DisplayClass142_3 again the closure class (see clause 3). <LoadGroups>b__3() is the anonymous method that you used in the LoadGroups method. Thus, this points to some anonymous method, which is a closure (captured external state) and which is called in the LoadGroups method.

+5
source share

All Articles