Ответ 1
Нет, нет, если вы не полностью замените каждый yield return
на один оператор return
, используя LINQ.
Например:
return someSet
.Concat(someOtherSet.SelectMany(s => FindSingle(context, s));
Я нахожусь слишком много для IEnumerables, чтобы я мог возвращать каждый результат. Есть ли способ сжать что-то вроде этого
foreach (var subSelector in subSelectors)
{
foreach (var node in FindSingle(context, subSelector))
yield return node;
}
Чтобы удалить внутренний foreach?
Нет, нет, если вы не полностью замените каждый yield return
на один оператор return
, используя LINQ.
Например:
return someSet
.Concat(someOtherSet.SelectMany(s => FindSingle(context, s));
Это несколько часто запрашиваемая функция, которую С# не поддерживает. Подробнее см. В разделе "Подключить":
Предлагаемый синтаксис обычно выглядит примерно так:
public static IEnumerable<T> PreorderTraversal<T>(this BinaryTree<T> root)
{
if (root == null) yield break;
yield return root.Item;
yield foreach root.Left.PreorderTraversal();
yield foreach root.Right.PreorderTraversal();
}
Если вы заинтересованы в игре на языке С#, который поддерживает эту функцию, посмотрите на Cω:
http://research.microsoft.com/en-us/um/cambridge/projects/comega/
Вы также можете прочитать эту статью об этой функции разработчиками Cω:
http://research.microsoft.com/en-us/projects/specsharp/iterators.pdf
Если вам интересен не-С# -подобный язык, поддерживающий эту функцию, взгляните на "выход!". функция F #. (Мне просто нравится, что название функции "yield!" )
Даже если вас не интересуют теоретические материалы, похоже, что вы сталкиваетесь с этой ситуацией как практическая проблема. Вы также должны прочитать статью Wes Dyer о методах эффективного выполнения такой вложенной итерации без "yield foreach":
http://blogs.msdn.com/b/wesdyer/archive/2007/03/23/all-about-iterators.aspx
Используйте Enumerable.SelectMany
:
return subSelectors.SelectMany(subselector => FindSingle(context, subSelector));
Это работает только в том случае, если в вашем методе нет других операторов возврата результата.
Вы можете разбить свой метод на два. Учитывая эти методы расширения:
public static class MultiEnumerableExtensions {
public static IEnumerable<T> Pack<T>(this T item) {
yield return item;
}
public static IEnumerable<T> Flatten<T>(
this IEnumerable<IEnumerable<T>> multiList) {
return multiList.SelectMany(x => x);
}
}
И используя Eric Lippert пример, он станет следующим:
public static class BinaryTreeExtensions {
public static IEnumerable<T> PreorderTraversal<T>(this BinaryTree<T> root) {
return PreorderTraversalMulti(root).Flatten();
}
private static IEnumerable<IEnumerable<T>> PreorderTraversalMulti<T>(
this BinaryTree<T> root) {
if (root == null) yield break;
yield return root.Item.Pack(); // this packs an item into an enumerable
yield return root.Left.PreorderTraversal();
yield return root.Right.PreorderTraversal();
}
}
Внутренний метод дает перечисления T вместо Ts, а внешний метод просто должен сгладить этот результат.
Используйте силу Linq!
return subSelectors.SelectMany(s => FindSingle(context, s));