У меня есть следующая функция, чтобы получить ошибки проверки для карты. Мой вопрос касается работы с GetErrors. Оба метода имеют одинаковый тип возвращаемого значения IEnumerable<ErrorInfo>
.
private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
var errors = GetMoreErrors(card);
foreach (var e in errors)
yield return e;
// further yield returns for more validation errors
}
Можно ли вернуть все ошибки GetMoreErrors
без необходимости перечислять их?
Думая об этом, это, вероятно, глупый вопрос, но я хочу убедиться, что я не ошибаюсь.
c#
ienumerable
yield
yield-return
Джон Оксли
источник
источник
GetCardProductionValidationErrorsFor
?Ответы:
Это определенно не глупый вопрос, и это то, что F # поддерживает
yield!
для всей коллекции противyield
одного элемента. (Это может быть очень полезно с точки зрения рекурсии хвоста ...)К сожалению, это не поддерживается в C #.
Однако, если у вас есть несколько методов, возвращающих каждый
IEnumerable<ErrorInfo>
, вы можете использовать егоEnumerable.Concat
для упрощения кода:Там одна очень важная разница между этими двумя реализациями , хотя: это один будет называть все методы сразу , даже если он будет использовать только возвращаемую итераторы по одному. Ваш существующий код будет ждать, пока он не пройдет через все,
GetMoreErrors()
прежде чем он даже спросит о следующих ошибках.Обычно это не важно, но стоит понимать, когда это произойдет.
источник
GetOtherErrors()
(и т. Д.) Откладывают их результаты (поскольку они реализованы с использованием блоков итераторов). Попробуйте изменить их, чтобы получить новый массив или что-то в этом роде, и вы поймете, что я имею в виду.Вы можете настроить все источники ошибок, как это (имена методов заимствованы из ответа Джона Скита).
Затем вы можете перебирать их одновременно.
В качестве альтернативы вы можете сгладить источники ошибок с помощью
SelectMany
.Выполнение методов
GetErrorSources
также будет отложено.источник
Я придумал быстрый
yield_
фрагмент:Вот фрагмент XML:
источник
yield!
, как в F #.Я не вижу ничего плохого в вашей функции, я бы сказал, что она делает то, что вы хотите.
Думайте о Yield как о возврате элемента в окончательном перечислении каждый раз, когда он вызывается, поэтому, когда вы используете его в цикле foreach, как этот, каждый раз, когда он вызывается, он возвращает 1 элемент. У вас есть возможность поместить условные выражения в ваш foreach для фильтрации набора результатов. (просто не поддаваясь критериям исключения)
Если вы добавите последующие выходы позже в методе, он будет продолжать добавлять 1 элемент в перечисление, что позволяет делать такие вещи, как ...
источник
Я удивлен, что никто не думал порекомендовать простой метод Extension,
IEnumerable<IEnumerable<T>>
чтобы этот код сохранял свое отложенное выполнение. Я являюсь поклонником отложенного выполнения по многим причинам, одна из них заключается в том, что объем памяти невелик даже для огромных чисел.И вы можете использовать его в вашем случае, как это
Точно так же вы можете покончить с функцией оболочки
DoGetErrors
и просто перейтиUnWrap
к месту вызова.источник
DoGetErrors(card).SelectMany(x => x)
делает то же самое и сохраняет отложенное поведение. Это именно то, что Адам предлагает в своем ответе .Да можно вернуть все ошибки сразу. Просто верните
List<T>
илиReadOnlyCollection<T>
.Возвращая,
IEnumerable<T>
вы возвращаете последовательность чего-то. На первый взгляд это может показаться идентичным возвращению коллекции, но есть ряд отличий, о которых следует помнить.Коллекции
Последовательности
IEnumerable<T>
допускает ленивую оценку, возвратList<T>
- нет).источник