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;
}
}
}
下载
转载请遵循此协议:署名 - 非商业用途 - 保持一致
并保留此链接:http://skyd.cnblogs.com/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述