假设我想枚举一个给定目录的文件&目录迭代,以这种方式首先发出内部目录和文件。
如果要在foreach循环中使用函数执行此枚举:DeleteFile和DeleteEmptyDirectory,它不应该失败,因为最内部的项目首先被放弃。
现在当然可以做到这一点(伪代码):
func(Directory dir)
foreach (var f in dir.EnumerateFileSystemInfos())
if (f is FileInfo)
yield return f;
else
foreach (var item in func(f))
yield return item;
yield return dir;
但是这会在调查员身上浪费大量的分配。
也可以使用两个堆栈"获取"将所有目录放在一起,然后只是不断弹出项目,但这会浪费太多内存,并且不能很好地平衡MoveNext时间。
关于如何有效地做到这一点而不浪费太多空间的任何想法?
答案 0 :(得分:1)
本着DRY原则的精神,我会使用我对How to make an IEnumerable of values of tree nodes?的回答中的函数
public static class TreeHelper
{
public static IEnumerable<T> Traverse<T>(T node, Func<T, IEnumerable<T>> childrenSelector, bool preOrder = true)
{
var stack = new Stack<IEnumerator<T>>();
var e = Enumerable.Repeat(node, 1).GetEnumerator();
try
{
while (true)
{
while (e.MoveNext())
{
var item = e.Current;
var children = childrenSelector(item);
if (children == null)
yield return item;
else
{
if (preOrder) yield return item;
stack.Push(e);
e = children.GetEnumerator();
}
}
if (stack.Count == 0) break;
e.Dispose();
e = stack.Pop();
if (!preOrder) yield return e.Current;
}
}
finally
{
e.Dispose();
while (stack.Count != 0) stack.Pop().Dispose();
}
}
}
在你的情况下使用它会是这样的
var directory = new DirectoryInfo(path);
var result = TreeHelper.Traverse<FileSystemInfo>(directory, fsi =>
fsi is DirectoryInfo ? ((DirectoryInfo)fsi).EnumerateFileSystemInfos() : null,
preOrder: false)