Умное использование .Net 2 итераторов

С# 2 и VB.Net 8 появилась новая функция, называемая итераторы, которые были разработаны для облегчения возврата счетчиков и счетчиков.

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

Какие нестандартные применения итераторов вы видели в реальном коде?

Ответы

Ответ 1

Я использовал их для написания системы в ASP.NET для создания серии взаимосвязанных взаимодействий страниц. Если вы представляете себе пользовательский разговор с веб-сайтом в виде серии запросов и ответов, вы можете моделировать взаимодействие как IEnumerable. Концептуально, например:

IEnumerable<PageResponse> SignupProcess(FormValues form)
{
   // signup starts with a welcome page, asking
   // the user to accept the license.
   yield return new WelcomePageResponse();

   // if they don't accept the terms, direct 
   // them to a 'thanks anyway' screen
   if (!form["userAcceptsTerms"])
   {
      yield return new ThanksForYourTimePageResponse();
      yield break;
   }

   // On the second page, we gather their email;
   yield new EmailCapturePage("");
   while(!IsValid(form["address"]))
   {
     // loop until we get a valid address.
     yield return new EmailCapturePage("The email address is incorrect. Please fix.");
   } 
}

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

Ответ 2

Чтобы начать работу:

  • Джеффри Рихтер написал мощную систему потоков, называемую AsyncEnumerator, используя итераторы. Он описан в журнале MSDN, один и два.
  • Итераторы также могут использоваться для ожидания взаимодействия пользовательского интерфейса внутри метода без блокировки потока пользовательского интерфейса, как я описал здесь.
  • В аналогичном ключе я использовал итераторы для создания веб-скребка на основе IE, используя методы скремблирования, которые возвращают IEnumerators WebAction, которые возвращаются в перечислитель при готовности. (Как правило, когда документ заканчивает загрузку).
    Если люди заинтересованы, я могу опубликовать его здесь.

Ответ 3

Я использовал его для рекурсивного перебора файлов, содержащихся в папке, ее подпапках и т.д. Для каждого файла я должен был выполнить определенное действие. Рекурсивная функция с утверждениями "return return" была простой для понимания всеми.

Ответ 4

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

static member generatePrimeNumbers max =    
    let rec generate number numberSequence =
        if number * number > max then numberSequence else
        let filteredNumbers = numberSequence |> Seq.filter (fun v -> v = number || v % number <> 0L)
        let newNumberSequence = seq { for i in filteredNumbers -> i }
        let newNumber = newNumberSequence |> Seq.find (fun x -> x > number)
        generate newNumber newNumberSequence                
    generate 2L (seq { for i in 2L..max -> i })

Ответ 5

Rhino.ETL сильно использует его для объединения преобразований по последовательности ввода

например, 3 операции, которые могут быть объединены, повторно использованы

public IEnumerable<Row> Execute(IEnumerable<Row> rows)
{
    foreach(var line in File.EnumerateLines())
    {
        var row = new Row();
        row["key"] = int.Parse(line.Substring(1));
        yield return row;
    }
}

public IEnumerable<Row> Execute(IEnumerable<Row> rows)
{
    foreach(var row in rows)
    {
        var value = (int)row["key"];
        row["key"] = value + 2;
        yield return row;
    }
}

public IEnumerable<Row> Execute(IEnumerable<Row> rows)
{
    using (var file = new Streamwriter(filename))
    {
        foreach(var row in rows)
        {
            file.WriteLine(row["key"]);
            yield return row;
        }
    }
}