RecursionSelect是一个极其方便的扩展方法,使用它仅需少量代码即可完成递归操作,从而大大提升编码速度和质量,此扩展方法在我的代码中被高频使用,这是我之前提供过的一个范例:
[TestMethod] public void TestMethod13() { //获取指定目录中所有包含子目录的目录集合 var d = new DirectoryInfo(@"C:\Users\Public\Downloads"); var c = d.RecursionSelect(f => f.GetDirectories(), f => f.GetDirectories().Length > 0); MessageBox.Show(c.Count().ToString()); }
此方法源于鹤冲天的这篇文章:http://www.cnblogs.com/ldp615/archive/2009/11/09/1599312.html
我曾在我的这篇文章中分享过我自己的实现版本(即RecursionSelect):http://www.cnblogs.com/SkyD/archive/2010/01/15/1648178.html
现在,我为其又追加了一点小小改进,通过新的重载形式方法,使其中的判断表达式可以用于中止递归,这样就变得更灵活许多。
具体为:增加了一个布尔类型参数,名为“检验失败是否继续”,此前默认的执行方式都是“true”,即“即使判断失败也会继续下面的递归”,这样判断表达式仅能起到一个过滤作用(类似Linq中的where),而如果将其设为false,就能够在第一次失败时阻断后面的一切操作,这在很多情况下非常有用(比如获取有共同特征的连续的对象链)。
现在的完整代码如下(新增的重载加粗显示):
/// <summary>
/// 循环所有子项,递归选取并返回所有后代项,针对IEnumerable
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="递归项选取表达式">通过此表达式选取要返回的子项</param>
/// <returns>选取的子项</returns>
public static IEnumerable<T> RecursionEachSelect<T>(this IEnumerable o, Func<T, IEnumerable<T>> 递归项选取表达式)
{
return RecursionEachSelect(o, 递归项选取表达式, null);
}/// <summary>
/// 循环所有子项,递归选取并返回所有后代项,针对IEnumerable
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="递归项选取表达式">通过此表达式选取要返回的子项</param>
/// <param name="检验表达式">対返回项进行检验,返回代入此表达式后表达式成立的项</param>
/// <returns>选取的子项</returns>
public static IEnumerable<T> RecursionEachSelect<T>(this IEnumerable o, Func<T, IEnumerable<T>> 递归项选取表达式, Predicate<T> 检验表达式)
{
return RecursionEachSelect(o.Cast<T>(), 递归项选取表达式, 检验表达式);
}/// <summary>
/// 循环所有子项,递归选取并返回所有后代项,针对IEnumerable泛型形式
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="递归项选取表达式">通过此表达式选取要返回的子项</param>
/// <returns>选取的子项</returns>
public static IEnumerable<T> RecursionEachSelect<T>(this IEnumerable<T> o, Func<T, IEnumerable<T>> 递归项选取表达式)
{
return RecursionEachSelect(o, 递归项选取表达式, null);
}/// <summary>
/// 循环所有子项,递归选取并返回所有后代项,针对IEnumerable泛型形式
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="递归项选取表达式">通过此表达式选取要返回的子项</param>
/// <param name="检验表达式">対返回项进行检验,返回代入此表达式后表达式成立的项</param>
/// <returns>选取的子项</returns>
public static IEnumerable<T> RecursionEachSelect<T>(this IEnumerable<T> o, Func<T, IEnumerable<T>> 递归项选取表达式, Predicate<T> 检验表达式)
{
return RecursionEachSelect(o, 递归项选取表达式, 检验表达式, true);
}/// <summary>
/// 循环所有子项,递归选取并返回所有后代项,针对IEnumerable泛型形式
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="递归项选取表达式">通过此表达式选取要返回的子项</param>
/// <param name="检验表达式">対返回项进行检验,返回代入此表达式后表达式成立的项</param>
/// <param name="检验失败是否继续">指示表达式检验失败后是否继续递归选取接下来的项,在不指定此参数的重载形式中默认为true</param>
/// <returns>选取的子项</returns>
public static IEnumerable<T> RecursionEachSelect<T>(this IEnumerable<T> o, Func<T, IEnumerable<T>> 递归项选取表达式, Predicate<T> 检验表达式, bool 检验失败是否继续)
{
foreach (var f in o)
{
bool? b = 检验表达式 == null ? (bool?)null : 检验表达式(f);
if (b == null || b.Value) yield return f;
else if (!检验失败是否继续)
{
yield break;
}
foreach (var d in RecursionSelect(f, 递归项选取表达式, 检验表达式))
{
yield return d;
}
}
}/// <summary>
/// 递归选取并返回后代项
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="递归项选取表达式">通过此表达式选取要返回的子项</param>
/// <returns>选取的子项</returns>
public static IEnumerable<T> RecursionSelect<T>(this T o, Func<T, T> 递归项选取表达式)
{
return RecursionSelect(o, 递归项选取表达式, null);
}/// <summary>
/// 递归选取并返回后代项
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="递归项选取表达式">通过此表达式选取要返回的子项</param>
/// <param name="检验表达式">対返回项进行检验,返回代入此表达式后表达式成立的项</param>
/// <returns>选取的子项</returns>
public static IEnumerable<T> RecursionSelect<T>(this T o, Func<T, T> 递归项选取表达式, Predicate<T> 检验表达式)
{
return RecursionSelect(o, 递归项选取表达式, 检验表达式, true);
}/// <summary>
/// 递归选取并返回后代项
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="递归项选取表达式">通过此表达式选取要返回的子项</param>
/// <param name="检验表达式">対返回项进行检验,返回代入此表达式后表达式成立的项</param>
/// <param name="检验失败是否继续">指示表达式检验失败后是否继续递归选取接下来的项,在不指定此参数的重载形式中默认为true</param>
/// <returns>选取的子项</returns>
public static IEnumerable<T> RecursionSelect<T>(this T o, Func<T, T> 递归项选取表达式, Predicate<T> 检验表达式, bool 检验失败是否继续)
{
if (o == null) yield break;
var f = 递归项选取表达式(o);
bool? b = 检验表达式 == null ? (bool?)null : 检验表达式(f);
if (b == null || b.Value) yield return f;
else if (!检验失败是否继续)
{
yield break;
}
foreach (var d in RecursionSelect(f, 递归项选取表达式, 检验表达式, 检验失败是否继续))
{
yield return d;
}
}/// <summary>
/// 递归选取并返回后代项
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="递归项选取表达式">通过此表达式选取要返回的子项</param>
/// <returns>选取的子项</returns>
public static IEnumerable<T> RecursionSelect<T>(this T o, Func<T, IEnumerable<T>> 递归项选取表达式)
{
return RecursionSelect(o, 递归项选取表达式, null);
}/// <summary>
/// 递归选取并返回后代项
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="递归项选取表达式">通过此表达式选取要返回的子项</param>
/// <param name="检验表达式">対返回项进行检验,返回代入此表达式后表达式成立的项</param>
/// <returns>选取的子项</returns>
public static IEnumerable<T> RecursionSelect<T>(this T o, Func<T, IEnumerable<T>> 递归项选取表达式, Predicate<T> 检验表达式)
{
return RecursionSelect(o, 递归项选取表达式, 检验表达式, true);
}/// <summary>
/// 递归选取并返回后代项
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="递归项选取表达式">通过此表达式选取要返回的子项</param>
/// <param name="检验表达式">対返回项进行检验,返回代入此表达式后表达式成立的项</param>
/// <param name="检验失败是否继续">指示表达式检验失败后是否继续递归选取接下来的项,在不指定此参数的重载形式中默认为true</param>
/// <returns>选取的子项</returns>
public static IEnumerable<T> RecursionSelect<T>(this T o, Func<T, IEnumerable<T>> 递归项选取表达式, Predicate<T> 检验表达式, bool 检验失败是否继续)
{
foreach (var f in 递归项选取表达式(o))
{
bool? b = 检验表达式 == null ? (bool?)null : 检验表达式(f);
if (b == null || b.Value) yield return f;
else if (!检验失败是否继续)
{
yield break;
}
foreach (var d in RecursionSelect(f, 递归项选取表达式, 检验表达式))
{
yield return d;
}
}
}