我想让没有显式循环的路径的所有父节点,以便我可以完全消除这种方法。
private static IEnumerable<string> GetParentPaths(string path)
{
while (Path.GetDirectoryName(path) != Path.GetPathRoot(path))
{
path = Path.GetDirectoryName(path);
yield return path;
}
}
如何用LINQ干净利落地完成这项工作?
给定的
c:\a\b\c
应该返回以下内容(顺序无关紧要)
c:\a
c:\a\b
更新
@Tomas Petricek的回答让我Jon Skeet's Generator implementation,我最终得到了以下内容:
path.Generate(Path.GetDirectoryName)
.Skip(1) // the original
.TakeWhile(p => p != Path.GetPathRoot(p))
使用
public static class TExtensions
{
public static IEnumerable<T> Generate<T>(this T initial, Func<T, T> next)
{
var current = initial;
while (true)
{
yield return current;
current = next(current);
}
}
}
答案 0 :(得分:4)
Enumerable
提供的标准方法不够强大,无法轻松编码while
循环。如果要通过调用某些通用方法来重写代码,则还需要实现一些通用方法。如果您添加了Generate
方法,则可以很好地解决您的问题:
EnumerableEx.Generate(path, path =>
Path.GetDirectoryName(path) != Path.GetPathRoot(path)
? Path.GetDirectoryName(path) : null);
Generate
方法的想法是它不断调用提供的lambda函数来生成新状态(在本例中为path
),直到它返回null
。该方法产生所有生成的值。您可以这样写Generate
:
static IEnumerable<T> Generate<T>(T initial, Func<T, T> next) {
T current = initial;
while(true) {
current = next(current);
if (current == default(T)) return;
yield return current;
}
}
该方法基本上只隐藏了原始方法中使用的可重用模式。特定行为作为函数传递,因此您可以将该方法用于许多不同的目的。