LINQ和递归

考虑以下:

public class Box { public BoxSize Size { get; set; } public IEnumerable Contents { get; set; } } Box FindBoxBySize(Box box, BoxSize size) { Box _foundBox = null; Action<IEnumerable> _recurse = null; _recurse = new Action<IEnumerable>(boxes => { foreach (var _box in boxes) { if (_box.Size == size) { _foundBox = _box; return; } if (_box.Contents != null) _recurse(_box.Contents); } }); _recurse(box.Contents); return _foundBox; } 

有没有什么方法可以使用LINQ压缩FindBoxBySize() ? 另外:欢迎对我的代码发表评论。 我没有做太多的递归,所以我可能在实现中遗漏了一些东西。

我也采用扩展方法方法,但使用迭代器方法:

 public static class BoxEx { public static IEnumerable Flatten(this Box box) { yield return box; if (box.Contents != null) { foreach (var b in box.Contents.SelectMany(b2 => Flatten(b2))) { yield return b; } } } } 

您的FindBoxBySize方法现在变为:

 Box FindBoxBySize(Box box, BoxSize size) { return (from b in box.Flatten() where b.Size == size select b).FirstOrDefault(); } 

您的原始呼叫代码无需修改即可运行

 var small = FindBoxBySize(box, BoxSize.Small); 

扩展方法:

 class Box { public IEnumerable GetBoxes() { // avoid NullReferenceException var contents = this.Contents ?? Enumerable.Empty(); // do the recursion return contents.SelectMany(b => b.GetBoxes()).Concat(contents); } public Box GetBox(int size) { return this.GetBoxes().FirstOrDefault(b => b.Size == size); } } 

用法:

 var box_with_box = new Box { Contents = new[] { new Box() { Size = 10 } } }; var box = new Box { Contents = new[] { box_with_box, box_with_box } }; Box box10 = box.GetBox(10); 

如果你想使用LINQ,你可以做这样的事情(未经测试):

 public static IEnumerable GetBoxesRecursive(this Box box) { if(box == null) throw new ArgumentNullException("box"); var children = box.Contents ?? Enumerable.Empty(); // use lambda in C# 3.0 var recursiveChildren = children.SelectMany(GetBoxesRecursive); return new[] { box }.Concat(recursiveChildren); } ... Box desiredBox = myBox.GetBoxesRecursive() .FirstOrDefault(b => b.Size == desiredSize); 

你可以通过写作让你的递归更清晰(在我看来)

 Box FindBoxBySize(Box box, BoxSize size) { if (box.Size == size) return box; foreach (var child in box.Contents) { var foundBox = FindBoxBySize(child, size); if(foundBox != null) return foundBox; } return null; } 

对于LINQ:LINQ没有一种处理递归数据结构的好方法。 可以通过向谷歌询问“LINQ递归”找到几种不同的扩展方法来解决,但我不确定它们是否在这种情况下增加了清晰度。