What is the yield keyword used for in C#?

后端 未结 17 1675
盖世英雄少女心
盖世英雄少女心 2020-11-22 05:26

In the How Can I Expose Only a Fragment of IList<> question one of the answers had the following code snippet:

IEnumerable FilteredList()
{
         


        
                      
相关标签:
17条回答
  • 2020-11-22 05:58

    The yield keyword actually does quite a lot here.

    The function returns an object that implements the IEnumerable<object> interface. If a calling function starts foreaching over this object, the function is called again until it "yields". This is syntactic sugar introduced in C# 2.0. In earlier versions you had to create your own IEnumerable and IEnumerator objects to do stuff like this.

    The easiest way understand code like this is to type-in an example, set some breakpoints and see what happens. Try stepping through this example:

    public void Consumer()
    {
        foreach(int i in Integers())
        {
            Console.WriteLine(i.ToString());
        }
    }
    
    public IEnumerable<int> Integers()
    {
        yield return 1;
        yield return 2;
        yield return 4;
        yield return 8;
        yield return 16;
        yield return 16777216;
    }
    

    When you step through the example, you'll find the first call to Integers() returns 1. The second call returns 2 and the line yield return 1 is not executed again.

    Here is a real-life example:

    public IEnumerable<T> Read<T>(string sql, Func<IDataReader, T> make, params object[] parms)
    {
        using (var connection = CreateConnection())
        {
            using (var command = CreateCommand(CommandType.Text, sql, connection, parms))
            {
                command.CommandTimeout = dataBaseSettings.ReadCommandTimeout;
                using (var reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        yield return make(reader);
                    }
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 06:01

    Recently Raymond Chen also ran an interesting series of articles on the yield keyword.

    • The implementation of iterators in C# and its consequences (part 1)
    • The implementation of iterators in C# and its consequences (part 2)
    • The implementation of iterators in C# and its consequences (part 3)
    • The implementation of iterators in C# and its consequences (part 4)

    While it's nominally used for easily implementing an iterator pattern, but can be generalized into a state machine. No point in quoting Raymond, the last part also links to other uses (but the example in Entin's blog is esp good, showing how to write async safe code).

    0 讨论(0)
  • 2020-11-22 06:02

    If I understand this correctly, here's how I would phrase this from the perspective of the function implementing IEnumerable with yield.

    • Here's one.
    • Call again if you need another.
    • I'll remember what I already gave you.
    • I'll only know if I can give you another when you call again.
    0 讨论(0)
  • 2020-11-22 06:03

    It's trying to bring in some Ruby Goodness :)
    Concept: This is some sample Ruby Code that prints out each element of the array

     rubyArray = [1,2,3,4,5,6,7,8,9,10]
        rubyArray.each{|x| 
            puts x   # do whatever with x
        }
    

    The Array's each method implementation yields control over to the caller (the 'puts x') with each element of the array neatly presented as x. The caller can then do whatever it needs to do with x.

    However .Net doesn't go all the way here.. C# seems to have coupled yield with IEnumerable, in a way forcing you to write a foreach loop in the caller as seen in Mendelt's response. Little less elegant.

    //calling code
    foreach(int i in obCustomClass.Each())
    {
        Console.WriteLine(i.ToString());
    }
    
    // CustomClass implementation
    private int[] data = {1,2,3,4,5,6,7,8,9,10};
    public IEnumerable<int> Each()
    {
       for(int iLooper=0; iLooper<data.Length; ++iLooper)
            yield return data[iLooper]; 
    }
    
    0 讨论(0)
  • 2020-11-22 06:04

    Yield has two great uses,

    1. It helps to provide custom iteration without creating temp collections.

    2. It helps to do stateful iteration.

    In order to explain above two points more demonstratively, I have created a simple video you can watch it here

    0 讨论(0)
提交回复
热议问题