私は定期的に再帰IEnumerable<T>
イテレータを書いて、たとえばXContainer.Descendants
. 私が実装し続けているパターンは次のとおりFoo
ですChildren
。
public static IEnumerable<Foo> Descendants(this Foo root) {
foreach (var child in root.Children()) {
yield return child;
foreach (var subchild in child.Descendants()) {
yield return subchild;
}
}
}
この古い StackOverflow の質問は、同じパターンを示唆しています。root
しかし、何らかの理由で、3 つのレベルの階層 ( 、child
、および)を参照する必要があるのは奇妙に感じますsubchild
。この基本的な深さ優先の再帰パターンをさらに減らすことはできますか? それとも、これは一種のアルゴリズムのプリミティブですか?
私が思いつく最善の方法は、パターンを一般的な拡張に抽象化することです。これにより、上記の反復子パターンのロジックが縮小されることはありませんが、Descendants
複数の特定のクラスに対してメソッドを定義する必要がなくなります。欠点として、これはそれ自体に拡張メソッドを追加しObject
ますが、これは少し臭いです:
public static IEnumerable<T> SelectRecurse<T>(
this T root, Func<T, IEnumerable<T>> enumerator) {
foreach (T item in enumerator(root))
{
yield return item;
foreach (T subitem in item.SelectRecurse(enumerator))
{
yield return subitem;
}
}
}
// Now we can just write:
foreach(var item in foo.SelectRecurse(f => f.Children())) { /* do stuff */ }