在While循环中使用收益(PriorityQueue实现) [英] Using Yield Within While Loop (PriorityQueue Implementation)

查看:95
本文介绍了在While循环中使用收益(PriorityQueue实现)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近,我一直在研究PriorityQueue类的各种实现,并且遇到一些我不完全了解的行为.

I have been playing around with various implementations of a PriorityQueue class lately, and I have come across some behavior I do not fully understand.

这是我正在运行的单元测试的一个片段:

Here, is a snippet from the unit test I am running:

        PriorityQueue<Int32> priorityQueue = new PriorityQueue<Int32>();
        Randomizer r = new Randomizer();
        priorityQueue.AddRange(r.GetInts(Int32.MinValue, Int32.MaxValue, r.Next(300, 10000)));

        priorityQueue.PopFront(); // Gets called, and works correctly

        Int32 numberToPop = priorityQueue.Count / 3;
        priorityQueue.PopFront(numberToPop); // Does not get called, an empty IEnumberable<T> (T is an Int32 here) is returned

正如我在评论中指出的那样,PopFront()会被调用并正确运行,但是当我尝试调用PopFront(numberToPop)时,根本不会调用该方法,因为它甚至没有输入方法.

As I noted in the comments, the PopFront() gets called and operates correctly, but when I try to call the PopFront(numberToPop), the method does not get called at all, as in, it does not even enter the method.

以下是方法:

    public T PopFront()
    {
        if (items.Count == 0)
        {
            throw new InvalidOperationException("No elements exist in the queue");
        }

        T item = items[0];
        items.RemoveAt(0);
        return item;
    }

    public IEnumerable<T> PopFront(Int32 numberToPop)
    {
        Debug.WriteLine("PriorityQueue<T>.PopFront({0})", numberToPop);
        if (numberToPop > items.Count)
        {
            throw new ArgumentException(@"The numberToPop exceeds the number 
                                          of elements in the queue", "numberToPop");
        }

        while (numberToPop-- > 0)
        {
            yield return PopFront();
        }
    }

现在,以前,我已经实现了重载的PopFront函数,如下所示:

Now, previously, I had implemented the overloaded PopFront function like this:

    public IEnumerable<T> PopFront(Int32 numberToPop)
    {
        Console.WriteLine("PriorityQueue<T>.PopFront({0})", numberToPop);
        if (numberToPop > items.Count)
        {
            throw new ArgumentException(@"The numberToPop exceeds the number 
                                          of elements in the queue", "numberToPop");
        }

        var poppedItems = items.Take(numberToPop);
        Clear(0, numberToPop);
        return poppedItems;
    }

以前的实现(如上)按预期工作.说了这么多,我显然知道我对yield语句的使用是不正确的(很可能是因为我要删除PopFront()函数中的然后返回元素),但是我真正感兴趣的是为什么PopFront(Int32 numberToPop)甚至都不会被调用,如果没有调用,为什么它返回一个空的IEnumerable?

The previous implementation (above) worked as expected. With all that being said, I am obviously aware that my use of the yield statement is incorrect (most likely because I am removing then returning elements in the PopFront() function), but what I am really interested in knowing is why the PopFront(Int32 numberToPop) is never even called and, if it is not called, why then is it returning an empty IEnumerable?

对于造成这种情况的任何帮助/解释,我们深表感谢.

Any help/explanation to why this is occurring is greatly appreciated.

推荐答案

使用yield return时,编译器会为您创建一个状态机.您必须开始枚举(foreachToList)方法返回的IEnumerable<T>,您的代码才会开始执行.

When you use yield return, the compiler creates a state machine for you. Your code won't start executing until you start to enumerate (foreach or ToList) the IEnumerable<T> returned by your method.

yield文档

在foreach循环的迭代中,对元素调用MoveNext方法.该调用将执行MyIteratorMethod的主体,直到到达下一个yield return语句为止. yield return语句返回的表达式不仅确定要由循环主体使用的元素变量的值,而且还确定元素的Current属性(即IEnumerable).

On an iteration of the foreach loop, the MoveNext method is called for elements. This call executes the body of MyIteratorMethod until the next yield return statement is reached. The expression returned by the yield return statement determines not only the value of the element variable for consumption by the loop body but also the Current property of elements, which is an IEnumerable.

在foreach循环的每个后续迭代中,迭代器主体从其中断处继续执行,并在到达yield return语句时再次停止.当到达迭代器方法的结尾或yield break语句时,foreach循环完成.

On each subsequent iteration of the foreach loop, the execution of the iterator body continues from where it left off, again stopping when it reaches a yield return statement. The foreach loop completes when the end of the iterator method or a yield break statement is reached.

这篇关于在While循环中使用收益(PriorityQueue实现)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆