У меня есть объект (триггер), который содержит метод 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
. Рассматриваемые триггеры могут срабатывать не через равные промежутки времени, поэтому мы не можем каждый раз просто увеличивать фиксированное количество минут.