Когда использование паттерна итератор уместно, а в каких случаях нежелательно?
Какие подводные камни скрывает паттерн?
Например, у меня есть класс для чтения строк из файла:
public class FormattedFileReader{
private readonly string _path;
// ...
public static IEnumerable<string> ReadFromFile(){
foreach (var line in File.ReadLines(_path)){
yield return GetFormattedValue(line);
}
}
private string GetFormattedValue(string initial){
// ...
}
}
Что пишут про итераторы на MSDN
Скажу своё мнение насчёт использования итератора.
Когда бы не использовал я:
foreach
IEnumerator<T>
GetEnumerator()
yield return
и при этом нам лучше не держать открытым соединение, например, с БД длительное время, ведь мы точно не можем быть уверенными, что внутри вызывающего цикла foreach
мы в приемлемое время обойдём всю коллекцию и закроем соединение или обойдёт её кто-то другой, не посвещённый в наши планы относительно быстрого обхода коллекции.Примеры, где я считаю использование итератора очень даже уместным:
Обход части коллекции
/// <summary>
/// Класс-итератор для прохода по части исходной коллекции, реализующей <see cref="IReadOnlyList{T}"/>.
/// </summary>
/// <typeparam name="T"> Тип элементов коллекции. </typeparam>
public struct SubListIterator<T> : IEnumerable<T>
{
private readonly IReadOnlyList<T> _original;
private readonly int _start;
public SubListIterator(IReadOnlyList<T> original, int start, int length)
{
if (original == null)
{
throw new ArgumentNullException(nameof(original));
}
if (start < 0)
{
throw new ArgumentOutOfRangeException(nameof(start));
}
if (length < 0)
{
throw new ArgumentOutOfRangeException(nameof(length));
}
if (start + length > original.Count)
{
throw new Exception(
"The range exceeds the size of the original IReadOnlyList " +
$"({nameof(start)} + {nameof(length)} = {(start + length).ToString()}, size of IReadOnlyList = {original.Count}).");
}
Length = length;
_original = original;
_start = start;
}
public T this[int index]
{
get
{
if (index < 0 || index >= Length)
{
throw new IndexOutOfRangeException();
}
return _original[_start + index];
}
}
public int Length { get; }
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < Length; i++)
{
yield return _original[_start + i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Метод-расширение для итератора
public static class IReadOnlyListExtensions
{
public static IEnumerable<SubListIterator<T>> GetPart<T>(this IReadOnlyList<T> list, int partSize)
{
int newPartSize;
for (int i = 0; i < list.Count; i += newPartSize)
{
newPartSize = partSize + i > list.Count ? list.Count - i : partSize;
yield return new SubListIterator<T>(list, i, newPartSize);
}
}
}
Чтение из файла, если нам не принципиально закрывать это файл быстро
/// <summary>
/// Класс для чтения из файла данных по частям.
/// </summary>
public class TextFileIterator : IEnumerable<IReadOnlyList<string>>
{
private readonly string _pathToFile;
private readonly int _maxLines;
private readonly CancellationToken _cancellationToken;
private readonly Encoding _encoding;
public TextFileIterator(string pathToFile, int maxLines, CancellationToken cancellationToken, Encoding encoding = null)
{
Debug.Assert(maxLines > 0);
Debug.Assert(pathToFile != null);
Debug.Assert(cancellationToken != null);
_pathToFile = pathToFile;
_maxLines = maxLines;
_cancellationToken = cancellationToken;
if (encoding == null)
{
encoding = Encoding.UTF8;
}
_encoding = encoding;
}
public IEnumerator<IReadOnlyList<string>> GetEnumerator()
{
using (var file = new StreamReader(_pathToFile, _encoding))
{
var lines = new List<string>(_maxLines);
do
{
lines.Clear();
string line = null;
for (int i = 0; i < _maxLines; i++)
{
if ((line = file.ReadLine()) == null)
{
break;
}
if (_cancellationToken.IsCancellationRequested)
{
yield break;
}
lines.Add(line);
}
if (lines.Count > 0)
{
yield return lines.ToArray();
}
if (line == null)
{
break;
}
} while (!_cancellationToken.IsCancellationRequested);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Виртуальный выделенный сервер (VDS) становится отличным выбором
Получаю от сайта ответ в формате json ( сайт ) как можно максимально компактно распарсить такой json?
Подскажите пожалуйста, как пользоваться RichTextBox? Как вставлять текст и менять его внешний вид(цвет или задний фон отдельных слов и тп