【问题标题】:Does an IEnumerable have to use Yield to be deferredIEnumerable 是否必须使用 Yield 才能被延迟
【发布时间】:2012-03-05 08:12:45
【问题描述】:

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);
        }

【问题讨论】:

  • 您可以使用 clojure 语法或编写一个对象来做同样的事情,而无需我想。我不想写一个例子来完全回答这个问题。

标签: c#


【解决方案1】:

必须使用yield - 最终您可以通过编写自定义枚举器 (IEnumerator[&lt;T&gt;]) 和将操作延迟到第一个 MoveNext()。但是,实施起来非常痛苦。当然,如果您确实使用yield,则默认情况下会延迟实现(您可以使用两种方法使其不延迟 - 一种不使用yield,然后 访问数据后使用另一种方法(迭代器块)来实现枚举器。

坦率地说,编写枚举数既困难又麻烦。除非绝对必要,否则我会避免它。迭代器块很棒。

【讨论】:

    【解决方案2】:

    返回 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();
    }
    

    【讨论】:

    【解决方案3】:

    Deferred 和 eager 是对立的——lazy 只是 deferred 的同义词。

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

    在您的示例中,Power 是急切的,因为它计算一个数组并返回它。这与 PowerYieldEager 不同,后者在生成的 IEnumerable 被迭代之前不会构建数组。

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

    【讨论】:

    • 感谢您澄清 Bryan 的语言
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    • 2020-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多