2011-03-13 57 views
2

我想讓一個路徑的所有父母都沒有顯式循環,這樣我就可以完全消除這個方法。使用linq獲取路徑的所有父母

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

回答

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

的方法基本上只是隱藏了在你原來的方法所使用的可重複使用的模式。具體行爲作爲函數傳遞,因此您可以將該方法用於許多不同的目的。

+0

'current == default(T)'似乎沒有編譯,除非Generate方法用'where T:class'標記 - 同樣'return'在那行應該是'yield break' – Handcraftsman 2011-03-13 17:52:27

+0

@Handcraftsman:謝謝爲更正。 Stackoverflow沒有內置的C#編譯器:-)不幸的。 – 2011-03-13 18:12:24