В том же духе, что и другие ответы, но с немного более общим подходом ...
... почему бы не создать класс Decorator , который может обернуть существующую реализацию IEnumerable и вычислить статистику при прохождении других элементов.
Вот класс Counter
, который я только что создал вместе, но вы также можете создавать варианты для других типов агрегации.
public class Counter<T> : IEnumerable<T>
{
public int Count { get; private set; }
public Counter(IEnumerable<T> source)
{
mSource = source;
Count = 0;
}
public IEnumerator<T> GetEnumerator()
{
foreach (var T in mSource)
{
Count++;
yield return T;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
foreach (var T in mSource)
{
Count++;
yield return T;
}
}
private IEnumerable<T> mSource;
}
Вы можете создать три экземпляра Counter
:
- Один, чтобы обернуть
GetAllFiles()
подсчет общего количества файлов;
- Один, чтобы обернуть
GetMatches()
подсчет количества подходящих файлов; и
- Один, чтобы обернуть
GetMatchingLines()
Подсчет количества совпадающих строк.
Ключевым моментом этого подхода является то, что вы не накладываете несколько обязанностей на существующие классы / методы - метод GetMatchingLines()
обрабатывает только сопоставление, вы не просите его также отслеживать статистику.
Уточнение в ответ на комментарий Mitcham
:
Окончательный код будет выглядеть примерно так:
var files = new Counter<string>( GetAllFiles());
var matchingFiles = new Counter<string>(GetMatches( "*.txt", files ));
var contents = GetFileContents( matchingFiles );
var linesFound = new Counter<string>(GetMatchingLines( contents ));
foreach( var lineText in linesFound )
Console.WriteLine( "Found: " + lineText );
string message
= String.Format(
"Found {0} matches in {1} matching files. Scanned {2} files",
linesFound.Count,
matchingFiles.Count,
files.Count);
Console.WriteLine(message);
Обратите внимание, что это все еще функциональный подход - используются переменные неизменяемые (больше похоже на привязки , чем переменные), и общая функция не имеет побочных эффектов.