递归选取扩展方法(RecursionSelect)的新重载形式

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;
        }
    }
}

下载

本文的XPS版本:http://www.uushare.com/user/icesee/file/3504904

原文地址:https://www.cnblogs.com/SkyD/p/1824248.html