C # When IEnumerable and yield are used to return results and foreach is used, it is invalid to modify the variable value in the loop,

Source: Internet
Author: User

C # When IEnumerable and yield are used to return results and foreach is used, it is invalid to modify the variable value in the loop,

A strange problem occurs in the project. After the value of the List is modified in the foreach loop, it does not take effect. The reason is that it is used to obtain the value of the list. Yield return . The following describes the causes:

First, let's take a look at the official explanation of yield return.

You can use the yield return statement to return an element at a time.
Use the iterator method through foreach statements or LINQ queries. Each iteration of the foreach loop calls the iterator method. When the iterator method runs to the yield return statement, an expression is returned and the current position in the Code is retained. Execute the next time you call the iterator function to restart from this position.

In use, the result is: when the return value of the Function Using yield return is traversed, not all returned results are retrieved at a time, but only one result is returned at a time, when the loop goes to the next variable, the code is re-executed from the yield return position, and the next result is returned from the yield return again. Let's take a look at the Code (the numbers in the comments are the code execution sequence, separated by | when multiple executions are performed ):

Var list = GetEnumerable (); // GetEnumerable () foreach (var test in list) is not executed at this time) // 1 | 4 | 7 The GetEnumerable () method {test is entered only when in is executed. atr1 = 0; // 3 | 6 | 9} public IEnumerable <ListTest> GetEnumerable () {for (int I = 0; I <2; I ++) {yield return new ListTest () {atr1 = I + 1}; // 2 | 5 | 8 }}

From the code above, we can see that when a variable is actually used in the list, the code will actually be executed to get the variable.
The next feature of yield return is the reason why the modified value does not take effect in a loop:

Var list = GetEnumerable (); // GetEnumerable () foreach (var test in list) is not executed at this time) // 1 | 4 | 7 The GetEnumerable () method {test is entered only when in is executed. atr1 = 0; // 3 | 6 | 9} foreach (var test in list) // 10 | 13 | 16 {test. atr1 = 0; // 12 | 15 | 18} public IEnumerable <ListTest> GetEnumerable () {for (int I = 0; I <2; I ++) {yield return new ListTest () {atr1 = I + 1}; // 2 | 5 | 8 | 11 | 14 | 17 }}

In fact, there is a strange point here. Although we all cyclically list once and get all the returned results, the GetEnumerable () method will still be executed when the list is repeated, re-return all the results, that is, every time we use the function to return the results, it is a new variable. Therefore, the variable modified in the loop is only this variable, it does not affect future variables.
Here, we can think of another problem, that is, the function has a relatively time-consuming operation, and the function call uses the returned results multiple times, which will seriously affect the performance, the following is an experiment:

Stopwatch watch = new Stopwatch (); watch. start (); var list = GetEnumerable (); for (int I = 0; I <100; I ++) {list. toList (). forEach (o => Console. write (o. atr1);} watch. stop (); Console. writeLine ("time spent:" + watch. elapsedMilliseconds); public IEnumerable <ListTest> GetEnumerable () {Thread. sleep (10); // Add this step to lengthen the time to make the effect more obvious for (int I = 0; I <2; I ++) {yield return new ListTest () {atr1 = I + 1 };}}

The execution time of the function is as follows:

Therefore, it is time-consuming to use it multiple times.
How can we solve this problem if we don't want it?
One method does not use yield return. Another method is to convert the returned result to List:

var list = GetEnumerable().ToList();

Let's look at the time again:

In this usage, the function can be executed only once, which can greatly save performance and solve the problem.Change the variable value in a loop.
MSDN's explanation of yield is as follows;

Use the yield keyword in the statement to indicate that the method, operator, or get accessor where the keyword is located is an iterator. By using yield to define the iterator, you can define the IEnumerable and IEnumerator modes of the set type without other explicit classes.

Yield aims to make it easier to use the iterator. It is useful when only one result is returned.

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.