这很可能是用户错误(我有点希望如此)。我在C#中遇到一个奇怪的情况,如果我尝试在一个使用yield的方法中进行递归调用,它似乎不被尊重(即调用被忽略)。
以下程序说明了这一点:
// node in an n-ary tree
class Node
{
public string Name { get; set; }
public List<Node> ChildNodes { get; set; }
}
class Program
{
// walk tree returning all names
static IEnumerable<string> GetAllNames(IEnumerable<Node> nodes)
{
foreach (var node in nodes)
{
if (node.ChildNodes != null)
{
Console.WriteLine("[Debug] entering recursive case");
// recursive case, yield all child node names
GetAllNames(node.ChildNodes);
}
// yield current name
yield return node.Name;
}
}
static void Main(string[] args)
{
// initalize tree structure
var tree = new List<Node>
{
new Node()
{
Name = "One",
ChildNodes = new List<Node>()
{
new Node() {Name = "Two"},
new Node() {Name = "Three"},
new Node() {Name = "Four"},
}
},
new Node() {Name = "Five"}
};
// try and get all names
var names = GetAllNames(tree);
Console.WriteLine(names.Count());
// prints 2, I would expect it to print 5
}
}
答案 0 :(得分:3)
你正在打电话但没有采取任何措施。你需要在这里实际使用结果
static IEnumerable<string> GetAllNames(IEnumerable<Node> nodes) {
foreach (var node in nodes) {
if (node.ChildNodes != null) {
foreach (var childNode in GetAllNames(node.ChildNodes)) {
yield return childNode;
}
}
yield return node.Name;
}
}
答案 1 :(得分:2)
您没有返回递归调用的结果。
您需要yield return
从通话中返回的每件商品:
foreach(var x in GetAllNames(node.ChildNodes))
yield return x;
答案 2 :(得分:0)
这是一个非常有趣的问题,可能导致任意深度结构的大量资源利用。我认为Skeet先生提出了一种“扁平化”技术,但我不记得这种联系。这是我们根据他的想法使用的代码(它是IEnumerable上的扩展方法):
public static class IEnumerableExtensions
{
/// <summary>
/// Visit each node, then visit any child-list(s) the node maintains
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="subjects">IEnumerable to traverse/></param>
/// <param name="getChildren">Delegate to get T's direct children</param>
public static IEnumerable<T> PreOrder<T>(this IEnumerable<T> subjects, Func<T, IEnumerable<T>> getChildren)
{
if (subjects == null)
yield break;
// Would a DQueue work better here?
// A stack could work but we'd have to REVERSE the order of the subjects and children
var stillToProcess = subjects.ToList();
while (stillToProcess.Any())
{
// First, visit the node
T item = stillToProcess[0];
stillToProcess.RemoveAt(0);
yield return item;
// Queue up any children
if (null != getChildren)
{
var children = getChildren(item);
if (null != children)
stillToProcess.InsertRange(0, children);
}
}
}
}
这避免了递归和很多嵌套迭代器。然后你会打电话给它:
// try and get all names
var names = tree.PreOrder<Node>(n => n.ChildNodes);
现在这是一个“预购”,其中节点名称首先出现,但如果您愿意,可以轻松编写下订单。