У меня есть объект (триггер), который содержит метод GetNextFireTime(DateTimeOffset after), который возвращает значение в следующий раз, когда триггер сработает после данного ввода. Моя цель состоит в том, чтобы, учитывая ввод списка времен неизвестного размера n, а также времени начала, гарантировать, что список времен соответствует первым n раз, когда триггер сработает после времени запуска. Это довольно легко сделать вот так
void Test(ITrigger trigger, DateTimeOffset start, DateTimeOffset[] expectedFireTimes){
var nextFire = startTime;
foreach (var expectedFire in expectedFireTimes){
nextFire = trigger.GetFireTimeAfter(nextFire);
Assert.That(nextFire, Is.EqualTo(expectedFire));
}
}
Однако затем я решил, что предпочитаю рассматривать результаты испытаний как одно утверждение, а не утверждать элементы один за другим, так что, если первые два времени срабатывания верны, а третье неверно, результаты испытаний ясно показывают, что было сделано. ожидалось и что было обнаружено. Это можно сделать, создав список, а не утверждая в цикле:
void Test(ITrigger trigger, DateTimeOffset start, DateTimeOffset[] expectedFireTimes){
var nextFire = startTime;
var upcomingFireTimes = new List<DateTimeOffset>();
foreach (var expectedFire in expectedFireTimes){
nextFire = trigger.GetFireTimeAfter(nextFire);
upcomingFireTimes.Add(nextFire);
}
Assert.That(upcomingFireTimes, Is.EqualTo(expectedFireTimes));
}
Это тоже работает, но заставило меня задуматься о том, можно ли это сделать через Linq. Есть ли в Linq метод создания списка, в котором каждый элемент рассчитывается на основе начального начального числа и предыдущего элемента? Самое близкое, что я могу придумать, это Aggregate(), который принимает начальное значение и функцию, но возвращает только одно значение, и мне пришлось бы хранить отдельные элементы в списке внутри функции, что делает его очень похожим на цикл foreach выше. :
var upcomingFireTimes = new List<DateTimeOffset>();
expectedFireTimes.Aggregate(
startTime,
(seed, _) => {
var nextfire = trigger.GetFireTimeAfter(seed);
upcomingFireTimes.Add(nextFire);
return nextFire;
});
Моя цель — однострочный метод Linq, который вместо того, чтобы в конечном итоге возвращать только последнее вычисленное значение, как это делает Aggregate(), возвращает все значения, вычисленные по пути, например:
var upcomingFireTimes = expectedFireTimes.SomeLinqMethod(
startTime,
(seed, _) => trigger.GetFireTimeAfter(seed));





Ваш метод Linq — Select!
DateTime firetime = startTime;
var upcomingFireTimes = expectedFireTimes.Select(s => { return fireTime = trigger.GetFireTimeAfter(fireTime) } );
Вы можете генерировать все, что вам нужно, используя или не используя исходную коллекцию.
Вы можете звонить куда угодно. Посмотрите выше.
Это не вызывает метод
GetFireTimeAfter. Рассматриваемые триггеры могут срабатывать не через равные промежутки времени, поэтому мы не можем каждый раз просто увеличивать фиксированное количество минут.