Умное использование.Net 2 Iterators
C# 2 и VB.Net 8 представили новую функцию, называемую итераторы, которые были разработаны для облегчения возврата перечислимых и перечислителей.
Однако итераторы на самом деле представляют собой ограниченную форму сопрограмм, и их можно использовать для выполнения многих полезных задач, которые не имеют ничего общего с коллекциями объектов.
Какие нестандартные применения итераторов вы видели в реальном коде?
5 ответов
Я использовал их, чтобы написать систему в 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.");
}
}
Вы можете сохранить итератор в состоянии сеанса, чтобы, когда пользователь возвращается на сайт, вы просто извлекали итератор, перемещали итератор на следующую страницу и возвращали его для рендеринга. Сложные взаимодействия сайта кодируются в одном месте.
Для начала:
- Джеффри Рихтер написал мощную систему потоков AsyncEnumerator с использованием итераторов. Это описано в журнале MSDN, части первая и вторая.
- Итераторы также можно использовать для ожидания взаимодействия пользовательского интерфейса в методе, не блокируя поток пользовательского интерфейса, как я описал здесь.
- В том же духе я использовал итераторы для создания веб-скребка на основе IE с методами очистки, которые возвращают IEnumerators
WebAction
s, которые перезванивают в перечислитель, когда готовы. (Как правило, когда документ заканчивается загрузкой).
Если людям интересно, я могу опубликовать это здесь.
Я использовал его для рекурсивного перебора файлов, содержащихся в папке, ее подпапках и так далее. Для каждого файла мне нужно было выполнить определенное действие. Рекурсивная функция с операторами "yield return" была простой для понимания всех остальных.
Я написал эту функцию до того, как узнал об операторе ленивого выхода. Это рекурсивно создает массивный итератор и возвращает его. Это не совсем эффективно, но я думаю, что это умно.
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 })
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;
}
}
}