Умное использование .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;
}
}
}