What is the yield keyword used for in C#?

后端 未结 17 1644
盖世英雄少女心
盖世英雄少女心 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:57

    A list or array implementation loads all of the items immediately whereas the yield implementation provides a deferred execution solution.

    In practice, it is often desirable to perform the minimum amount of work as needed in order to reduce the resource consumption of an application.

    For example, we may have an application that process millions of records from a database. The following benefits can be achieved when we use IEnumerable in a deferred execution pull-based model:

    • Scalability, reliability and predictability are likely to improve since the number of records does not significantly affect the application’s resource requirements.
    • Performance and responsiveness are likely to improve since processing can start immediately instead of waiting for the entire collection to be loaded first.
    • Recoverability and utilisation are likely to improve since the application can be stopped, started, interrupted or fail. Only the items in progress will be lost compared to pre-fetching all of the data where only using a portion of the results was actually used.
    • Continuous processing is possible in environments where constant workload streams are added.

    Here is a comparison between build a collection first such as a list compared to using yield.

    List Example

        public class ContactListStore : IStore
        {
            public IEnumerable GetEnumerator()
            {
                var contacts = new List();
                Console.WriteLine("ContactListStore: Creating contact 1");
                contacts.Add(new ContactModel() { FirstName = "Bob", LastName = "Blue" });
                Console.WriteLine("ContactListStore: Creating contact 2");
                contacts.Add(new ContactModel() { FirstName = "Jim", LastName = "Green" });
                Console.WriteLine("ContactListStore: Creating contact 3");
                contacts.Add(new ContactModel() { FirstName = "Susan", LastName = "Orange" });
                return contacts;
            }
        }
    
        static void Main(string[] args)
        {
            var store = new ContactListStore();
            var contacts = store.GetEnumerator();
    
            Console.WriteLine("Ready to iterate through the collection.");
            Console.ReadLine();
        }
    

    Console Output
    ContactListStore: Creating contact 1
    ContactListStore: Creating contact 2
    ContactListStore: Creating contact 3
    Ready to iterate through the collection.

    Note: The entire collection was loaded into memory without even asking for a single item in the list

    Yield Example

    public class ContactYieldStore : IStore
    {
        public IEnumerable GetEnumerator()
        {
            Console.WriteLine("ContactYieldStore: Creating contact 1");
            yield return new ContactModel() { FirstName = "Bob", LastName = "Blue" };
            Console.WriteLine("ContactYieldStore: Creating contact 2");
            yield return new ContactModel() { FirstName = "Jim", LastName = "Green" };
            Console.WriteLine("ContactYieldStore: Creating contact 3");
            yield return new ContactModel() { FirstName = "Susan", LastName = "Orange" };
        }
    }
    
    static void Main(string[] args)
    {
        var store = new ContactYieldStore();
        var contacts = store.GetEnumerator();
    
        Console.WriteLine("Ready to iterate through the collection.");
        Console.ReadLine();
    }
    

    Console Output
    Ready to iterate through the collection.

    Note: The collection wasn't executed at all. This is due to the "deferred execution" nature of IEnumerable. Constructing an item will only occur when it is really required.

    Let's call the collection again and obverse the behaviour when we fetch the first contact in the collection.

    static void Main(string[] args)
    {
        var store = new ContactYieldStore();
        var contacts = store.GetEnumerator();
        Console.WriteLine("Ready to iterate through the collection");
        Console.WriteLine("Hello {0}", contacts.First().FirstName);
        Console.ReadLine();
    }
    

    Console Output
    Ready to iterate through the collection
    ContactYieldStore: Creating contact 1
    Hello Bob

    Nice! Only the first contact was constructed when the client "pulled" the item out of the collection.

提交回复
热议问题