IEnumerable是否必须使用Yield来延迟

时间:2012-02-13 22:07:34

标签: c#

IEnumerable是否必须使用Yield来延迟?

这是帮助我了解延期执行和收益的测试代码。

 //immediate execution
        public IEnumerable Power(int number, int howManyToShow)
        {
            var result = new int[howManyToShow];
            result[0] = number;
            for (int i = 1; i < howManyToShow; i++)
                result[i] = result[i - 1] * number;
            return result;
        }

        //deferred but eager
        public IEnumerable PowerYieldEager(int number, int howManyToShow)
        {
            var result = new int[howManyToShow];
            result[0] = number;
            for (int i = 1; i < howManyToShow; i++)
                result[i] = result[i - 1] * number;

            foreach (var value in result)
                yield return value;
        }

        //deferred and lazy
        public IEnumerable PowerYieldLazy(int number, int howManyToShow)
        {
            int counter = 0;
            int result = 1;
            while (counter++ < howManyToShow)
            {
                result = result * number;
                yield return result;
            }
        }

        [Test]
        public void Power_WhenPass2AndWant8Numbers_ReturnAnEnumerable()
        {
            IEnumerable listOfInts = Power(2, 8);

            foreach (int i in listOfInts)
                Console.Write("{0} ", i);
        }


        [Test]
        public void PowerYieldEager_WhenPass2AndWant8Numbers_ReturnAnEnumerableOfInts()
        {
            //deferred but eager execution
            IEnumerable listOfInts = PowerYieldEager(2, 8);

            foreach (int i in listOfInts)
                Console.Write("{0} ", i);
        }


        [Test]
        public void PowerYield_WhenPass2AndWant8Numbers_ReturnAnEnumerableOfIntsOneAtATime()
        {
            //deferred and lazy execution
            IEnumerable listOfInts = PowerYieldLazy(2, 8);

            foreach (int i in listOfInts)
                Console.Write("{0} ", i);
        }

3 个答案:

答案 0 :(得分:6)

使用yield - 最终您可以通过编写自定义枚举器(yield来完成{{1>}所做的一切 {1}})并将行动推迟到第一个IEnumerator[<T>]。但是,实施起来非常痛苦。当然,如果您执行使用MoveNext(),默认情况下会延迟实现(您可以使用两种方法使其不延迟 - 一种不使用yield的方法,然后访问数据之后使用另一个方法(迭代器块)来实现枚举器。

坦率地说,编写调查员很难并且错误。除非绝对必要,否则我会避免它迭代器块很棒。

答案 1 :(得分:1)

返回IEnumerable的函数(F1)可以返回在另一个函数(F2)中计算的IEnumerable,如果F2被延迟,则F1被推迟

例如,在以下代码中,F1和F2都是延迟的

public IEnumerable<int> F2()
{
    for (int i = 0; i < 10; i++) {
        yield return i;
    }
}

public IEnumerable<int> F1()
{
    return F2();
}

答案 2 :(得分:0)

延迟和渴望是对立的 - 懒惰只是延迟的同义词。

急切序列是预先计算的序列,例如列表或数组。延迟序列是在迭代时计算的序列。

在您的示例中,Power非常渴望,因为它会计算一个数组并将其返回。这与PowerYieldEager不同,后者在迭代生成的IEnumerable之前不会构建数组。

您可以将延迟与渴望视为序列的潜在与序列的内容。考虑到这一点,yield return只是推迟的一种方式;请求结果时计算的任何序列都是延迟序列。