How to pretty print the Iterator Method

363 views Asked by At

I want to get the method name with its arguments of Iterator Method and I am struggling to find a simple solution. Iterators are generated by a compiler as a result the source method name and it's arguments are now in a generated class name and it's fields respectively (with some magic <>+_d symbols).

In Immediate window of Visual Studio when I enter the iterator method I get the method name and it's arguments in a pretty way. Are they using some custom printers or maybe there is some helpers to do that?

Edit:

The main goal is to get the coroutine async call stack.

Program.Test(a, b)
  Program.TestB(b)

Here is an example:

using System;
using System.Collections;
using System.Linq;

class Program
{
    static IEnumerable TestB(string b)
    {
        yield return b;
        yield return b;
    }

    static IEnumerable Test(string a, string b)
    {
        yield return a;
        yield return TestB(b);
    }

    static void Main(string[] args)
    {
        var iterator = Test("foo", "bar");

        // Immediate Window
        // ================
        // iterator
        // {Program.Test}
        //     a: null
        //     b: null
        //     System.Collections.Generic.IEnumerator<System.Object>.Current: null
        //     System.Collections.IEnumerator.Current: null

        Console.WriteLine(iterator);
        // prints:
        // Program+<Test>d__0

        foreach (var field in iterator.GetType().GetFields())
            Console.WriteLine(field);
        // prints:
        // System.String a
        // System.String <>3__a
        // System.String b
        // System.String <>3__b
    }
}
1

There are 1 answers

0
jessehouwing On

You can use a DebuggerTypeProxy attribute and set it on your Program class. It would be very similar to the example given on the MSDN documentation page, which shows how to display a HashTable, instead of an Enumarable. It should be rather easy to convert this to use an Enumerable instead. You might need to create your own class that inherits from IEnumerable though for this to work. Not sure if it would work on a implicit enumerable, but then again, you're taking shortcuts here and want sugar coating, these often do not go well together.

[DebuggerDisplay("{value}", Name = "{key}")]
internal class KeyValuePairs
{
    private IDictionary dictionary;
    private object key;
    private object value;

    public KeyValuePairs(IDictionary dictionary, object key, object value)
    {
        this.value = value;
        this.key = key;
        this.dictionary = dictionary;
    }
}

[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(HashtableDebugView))]
class MyHashtable : Hashtable //this would be Program
{
    private const string TestString = "This should not appear in the debug window.";

    internal class HashtableDebugView
    {
        private Hashtable hashtable;
        public const string TestString = "This should appear in the debug window.";
        public HashtableDebugView(Hashtable hashtable)
        {
            this.hashtable = hashtable;
        }

        [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
        public KeyValuePairs[] Keys
        {
            get
            {
                KeyValuePairs[] keys = new KeyValuePairs[hashtable.Count];

                int i = 0;
                foreach(object key in hashtable.Keys)
                {
                    keys[i] = new KeyValuePairs(hashtable, key, hashtable[key]);
                    i++;
                }
                return keys;
            }
        }
    }
}