1

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
    }
}
mipi
  • 273
  • 4
  • 14
  • It's not clear what you mean by "the pretty print". What output were you *expecting*? – Jon Skeet Dec 31 '14 at 09:27
  • I want to get the method name and it's arguments. – mipi Dec 31 '14 at 09:31
  • The goal is to print: Program.Test(a, b) – mipi Dec 31 '14 at 10:03
  • But you've just got the result of calling the method. While you *could* do this by trying to match up the name of the type with a method, you'd have to consider what would happen if the method was overloaded - and also what you'd want to do if the implementation of the method changed to later not use an iterator block. (Suppose you decided to use LINQ instead, for example...) – Jon Skeet Dec 31 '14 at 10:30
  • I use iterative method to implement coroutines. This pretty print would allow to get the async calling stack the same way as a regular one. I think I should go with the above reflection with some regex... – mipi Jan 01 '15 at 16:08
  • If you're using it for *asynchrony*, why aren't you using `async`? – Jon Skeet Jan 01 '15 at 16:30
  • I have to target .net4 and I want to test, control and monitor the state of mmm state machine easily. – mipi Jan 01 '15 at 16:41
  • You can still use async with .net 4, with the BCL compatibility pack. – Jon Skeet Jan 01 '15 at 18:31
  • Oh, didn't know that. But still the testing is very easy with enumerable, you can test different scenarious just enumerating over. And it even works in NETMF. I think that async and coroutines can work together. – mipi Jan 03 '15 at 10:03

1 Answers1

0

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;
            }
        }
    }
}
jessehouwing
  • 106,458
  • 22
  • 256
  • 341