Назначение: Классическая pull-модель, где потребитель запрашивает данные по мере необходимости.
Характеристики:
Реализация:
IEnumerable<int> GetNumbers() {
yield return 1;
yield return 2;
}
Использование:
foreach (var num in GetNumbers()) {
Console.WriteLine(num);
}
Преимущества:
Назначение: Реактивная push-модель, где источник сам уведомляет подписчиков о новых данных.
Характеристики:
Реализация (System.Reactive):
IObservable<int> observable = Observable.Create<int>(observer => {
observer.OnNext(1);
observer.OnNext(2);
return Disposable.Empty;
});
Использование:
var subscription = observable.Subscribe(
x => Console.WriteLine(x),
ex => Console.Error.WriteLine(ex),
() => Console.WriteLine("Completed"));
Преимущества:
Назначение: Асинхронная pull-модель для работы с потоками данных с ожиданием.
Характеристики:
Реализация:
async IAsyncEnumerable<int> GetAsyncNumbers() {
await Task.Delay(100);
yield return 1;
await Task.Delay(100);
yield return 2;
}
Использование:
await foreach (var num in GetAsyncNumbers()) {
Console.WriteLine(num);
}
Преимущества:
Модель | Паттерн | Особенности | Типичные сценарии использования |
---|---|---|---|
IEnumerable<T> | Pull | Синхронный, ленивый | LINQ, обработка коллекций |
IObservable<T> | Push | Многоподписочный, реактивный | UI события, потоковые данные |
IAsyncEnumerable<T> | Async Pull | Асинхронный, ленивый | Асинхронные потоки данных |
// IEnumerable
var sum = numbers.Sum();
// IObservable
observable.Aggregate(0, (acc, x) => acc + x)
// IAsyncEnumerable
await asyncNumbers.SumAsync();
IEnumerable:
// Чтение большого файла построчно
IEnumerable<string> ReadLines(string path) {
using var reader = new StreamReader(path);
while (!reader.EndOfStream)
yield return reader.ReadLine();
}
IObservable:
// Отслеживание изменений файла
var watcher = new FileSystemWatcher();
IObservable<EventPattern<FileSystemEventArgs>> changes =
Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
h => watcher.Changed += h,
h => watcher.Changed -= h);
IAsyncEnumerable:
// Асинхронное чтение из базы данных
async IAsyncEnumerable<Product> GetProductsAsync() {
await using var connection = new SqlConnection(connString);
await connection.OpenAsync();
var command = new SqlCommand("SELECT * FROM Products", connection);
await using var reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync()) {
yield return MapProduct(reader);
}
}
каждая модель решает свои задачи - IEnumerable для синхронных pull-сценариев, IObservable для реактивных push-сценариев, и IAsyncEnumerable для асинхронных pull-потоков. Выбор зависит от требований к обработке данных: синхронность/асинхронность, push/pull модель, и необходимость реактивности.