Любой способ получить ссылку на «это» в сгенерированном блоке итератора? - PullRequest
3 голосов
/ 13 июля 2011

Начиная с C # 2.0, мы можем объявлять блоки итераторов внутри классов и возвращать значения из них, используя ключевые слова yield return. За кулисами компилятор щедро преобразовал наш довольно простой блок итератора в свой собственный класс, конечный автомат, который полностью реализует интерфейс IEnumerable или IEnumerator. Используя ILSpy или Reflector, вы можете получить представление о том, как выглядят эти классы.

В C # 3.5 к языку были добавлены методы расширения, обеспечивающие простые средства написания статических методов, которые появятся во всплывающем окне intellisense существующих классов или интерфейсов.

Что мне интересно, так это объединение этих двух концепций, и при этом у меня трудное время. Мое разочарование связано с тем фактом, что в блоке итератора ключевое слово 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";
    }
}

К сожалению, в этом контексте this относится к экземпляру IteratorExample, а не к экземпляру сгенерированного класса MyIterator. Есть ли способ получить ссылку в итераторе или мне придется пересмотреть свои планы?

Ответы [ 3 ]

3 голосов
/ 13 июля 2011

Нет чистого пути, нет. Все this использование перехвачено и относится к объявлению экземпляра.

Вы могли бы возможно сделать что-то ужасное, включая злоупотребление стеком или чем-то подобным, но ничего аккуратного не очевидно. Вы могли бы вместо этого связать итераторы в стиле LINQ? т.е.

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

и используйте originalIterator.WithLogging()

0 голосов
/ 13 июля 2011

Это не сработает, поэтому вам придется пересмотреть свои планы.

Если вы дадите больше информации о том, чего вы хотите достичь, мы сможем помочь вам найти альтернативное решение.

0 голосов
/ 13 июля 2011

Я не думаю, что вы сможете делать то, что вы хотите - я думаю, что языковая спецификация скрывает класс реализации, поэтому он не ограничивает будущие реализации той же функции, которая может использовать другой механизм.

...