Record the history of yield return ., Yieldreturn

Source: Internet
Author: User

Record the history of yield return ., Yieldreturn

The process is as follows:

I used C # To write a simple function that generates sequences through iteration.

public static IEnumerable<T> Iterate<T>(this Func<T, T> f, T initVal, int length){    Checker.NullCheck(nameof(f), f);        Checker.RangeCheck(nameof(length), length, 0, int.MaxValue);    var current = initVal;    while (--length >= 0)    {        yield return (current = f(current));    }}

NullCheck is used to check whether the parameter is null. If yes, an ArgumentNullException exception is thrown.

Correspondingly, I wrote the following unit test code to detect this exception.

public void TestIterate(){    Func<int, int> f = null;    Assert.Throws<ArgumentNullException>(() => f.Iterate(1, 7));        // Other tests}

However, this test was unexpectedly fail.

At first, I thought it was a problem with the NullCheck function, but I changed the NullCheck directly to the if statement.

Then I breakpoint and debug the Iterate function. Result The debugger did not stop at the breakpoint and ran the test directly.

I thought the method I tested was wrong, so I constantly modified the test code, and even thought it was a bug in. NET Unit Tests.

Finally, I found the problem in this test code:

Assert.Throws<ArgumentNullException>(() =>{    var seq = f.Iterate(1, 7);    foreach (int ele in seq)        Console.WriteLine(ele);});

When I debug this test, the program stops at the break point of my previous Iterate function.

As a result, I break a breakpoint on var seq = f. Iterate (1, 7); and run it gradually. At this time, I found that when the program runs var seq = f. Iterate (1, 7); it does not enter the Iterate function; instead, it only enters after the program runs the foreach statement.

This involves the specific workflow of yield return. When yield return appears in the function code, calling this function will return an IEnumerable <T> or IEnumerator <T> object, but will not execute any code in the function body. The function is executed only when you execute the IEnumerator <T> MoveNext () function of the returned IEnumerator <T> object obtained by calling the GetEnumerator method of the returned object.

Therefore, the preceding two checks are not executed during function calling, but are executed only when you start foreach.

This is not the result I want. I want to check the validity of the parameter when calling the function. If it is invalid, an exception is thrown directly.

There are two ways to solve this problem. One is to split it into two functions:

public static IEnumerable<T> Iterate<T>(this Func<T, T> f, T initVal, int length){    Checker.NullCheck(nameof(f), f);        Checker.RangeCheck(nameof(length), length, 0, int.MaxValue);                return IterateWithoutCheck(f, initVal, length);}private static IEnumerable<T> IterateWithoutCheck<T>(this Func<T, T> f, T initVal, int length){    var current = initVal;    while (--length >= 0)    {        yield return (current = f(current));    }}

Alternatively, you can wrap this function into a class.

    class FunctionIterator<T> : IEnumerable<T>    {        private readonly Func<T, T> f;        private readonly T initVal;        private readonly int length;                public FunctionIterator(Func<T, T> f, T initVal, int length)        {            Checker.NullCheck(nameof(f), f);            Checker.RangeCheck(nameof(length), length, 0, int.MaxValue);                        this.f = f;            this.initVal = initVal;            this.length = length;        }        public IEnumerator<T> GetEnumerator()        {            T current = initVal;            for (int i = 0; i < length; ++i)                yield return (current = f(current));        }        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()        {            return GetEnumerator();        }    }

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.