开发者

Any way to get a reference to "this" in a generated iterator block?

Since C# 2.0 we've been able to declare iterator blocks inside classes and r开发者_如何学运维eturn values from them using the yield return keywords. Behind the scenes the compiler has generously converted our rather simple iterator block into its own class, a state machine which fully implements either the IEnumerable or IEnumerator interface. Using ILSpy or Reflector you can get a glimps of what these classes look like.

In C# 3.5 Extension Methods were added to the language providing a simple means of writing static methods that will appear in existing classes or interfaces' intellisense popup.

What I am interested in doing is combining these two concepts and in doing so I'm having a difficult time. My frustration centers around the fact that in an iterator block, the this keyword refers to the class that the iterator block is in instead of the compiler generated class which holds the implementation of the iterator block.

What I'd like to do is something like this:

public static class IteratorExtensions
{
    public static void DoSomething<T>(this IEnumerable<T> iterator)
    {
        Console.WriteLine("Running iterator block of type :" + typeof(T).Name);
    }
}

public class IteratorExample
{
    public IEnumerable<string> MyIterator()
    {
        yield return "Hello";
        this.DoSomething();
        yield return "World";
    }
}

Unfortunately in this context this refers to an instance of IteratorExample and not to an instance of the generated MyIterator class. Is there any way to get a reference in the iterator or will I have to rethink my plans?


No clean way, no. All this usage is intercepted and refers to the declaring instance.

You could possibly do something horrible involving abusing the stack or similar, but nothing tidy is obvious. You could maybe chain the iterators LINQ-style instead? i.e.

public static IEnumerable<T> WithLogging<T>(this IEnumerable<T> source)
{
    source.DoSomething();
    try {
        foreach(var item in source) yield return item;
    } finally {
        source.DoSomethingElse();
    }
}

and use originalIterator.WithLogging()


I don't think you are going to be able to do what you want-- I think the language spec hides the implementation class so it doesn't constrain future implementations of the same feature that might use a different mechanism.


This will not work, so you will have to rethink your plans.

If you give more information about what you want to achieve we might be able to help you find an alternative solution.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜