用linq获取所有父母的路径

时间:2011-03-13 17:20:04

标签: c# linq path filepath

我想让没有显式循环的路径的所有父节点,以便我可以完全消除这种方法。

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

1 个答案:

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

该方法基本上只隐藏了原始方法中使用的可重用模式。特定行为作为函数传递,因此您可以将该方法用于许多不同的目的。