I could probably write this myself, but the specific way I\'m trying to accomplish it is throwing me off. I\'m trying to write a generic extension method similar to the oth
I thought I'd share a complete example with error handling and a single-logic apporoach.
Recursive flattening is as simple as:
LINQ version
public static class IEnumerableExtensions
{
public static IEnumerable SelectManyRecursive(this IEnumerable source, Func> selector)
{
if (source == null) throw new ArgumentNullException("source");
if (selector == null) throw new ArgumentNullException("selector");
return !source.Any() ? source :
source.Concat(
source
.SelectMany(i => selector(i).EmptyIfNull())
.SelectManyRecursive(selector)
);
}
public static IEnumerable EmptyIfNull(this IEnumerable source)
{
return source ?? Enumerable.Empty();
}
}
Non-LINQ version
public static class IEnumerableExtensions
{
public static IEnumerable SelectManyRecursive(this IEnumerable source, Func> selector)
{
if (source == null) throw new ArgumentNullException("source");
if (selector == null) throw new ArgumentNullException("selector");
foreach (T item in source)
{
yield return item;
var children = selector(item);
if (children == null)
continue;
foreach (T descendant in children.SelectManyRecursive(selector))
{
yield return descendant;
}
}
}
}
Design decisions
I decided to:
IEnumerable, this can be changed by removing exception throwing and:
source = source.EmptyIfNull(); before return in the 1st versionif (source != null) before foreach in the 2nd version.EmptyIfNull() in the first version - note that SelectMany will fail if null is returned by selectorif (children == null) continue; in the second version - note that foreach will fail on a null IEnumerable parameter.Where clause on the caller side or within the children selector rather than passing a children filter selector parameter:
Sample use
I'm using this extension method in LightSwitch to obtain all controls on the screen:
public static class ScreenObjectExtensions
{
public static IEnumerable FindControls(this IScreenObject screen)
{
var model = screen.Details.GetModel();
return model.GetChildItems()
.SelectManyRecursive(c => c.GetChildItems())
.OfType()
.Select(c => screen.FindControl(c.Name));
}
}