c# - सी#में उपयोग किए जाने वाले उपज कीवर्ड क्या है?




yield (14)

पुनरावृत्ति। यह "कवर के तहत" एक राज्य मशीन बनाता है जो याद करता है कि आप समारोह के प्रत्येक अतिरिक्त चक्र पर कहां थे और वहां से उठाते हैं।

मैं केवल IList के एक टुकड़े का पर्दाफाश कैसे कर सकता हूं <> प्रश्नों में से एक के पास निम्न कोड स्निपेट था:

IEnumerable<object> FilteredList()
{
    foreach( object item in FullList )
    {
        if( IsItemInPartialList( item )
            yield return item;
    }
}

उपज कीवर्ड क्या करता है? मैंने इसे दो स्थानों और एक अन्य प्रश्न में संदर्भित किया है, लेकिन मुझे यह पता नहीं लगा है कि वास्तव में यह क्या करता है। मैं किसी अन्य धागे की उपज के भाव में उपज के बारे में सोचने के लिए प्रयोग किया जाता हूं, लेकिन यह यहां प्रासंगिक प्रतीत नहीं होता है।


यील्ड के दो महान उपयोग हैं,

  1. यह अस्थायी संग्रह बनाने के बिना कस्टम पुनरावृत्ति प्रदान करने में मदद करता है।

  2. यह राज्यपूर्ण पुनरावृत्ति करने में मदद करता है।

दो बिंदुओं से अधिक स्पष्ट रूप से व्याख्या करने के लिए, मैंने एक साधारण वीडियो बनाया है जिसे आप here देख सकते here


हाल ही में रेमंड चेन भी उपज कीवर्ड पर लेखों की एक दिलचस्प श्रृंखला चलाया।

हालांकि यह नामक रूप से एक इटरेटर पैटर्न को आसानी से कार्यान्वित करने के लिए उपयोग किया जाता है, लेकिन इसे राज्य मशीन में सामान्यीकृत किया जा सकता है। रेमंड को उद्धृत करने में कोई बात नहीं, अंतिम भाग अन्य उपयोगों से भी जुड़ा हुआ है (लेकिन एंटिन के ब्लॉग में उदाहरण एएसपी अच्छा है, यह दिखा रहा है कि एसिंक सुरक्षित कोड कैसे लिखना है)।


यह कुछ रूबी गुडनेस लाने की कोशिश कर रहा है :)
अवधारणा: यह कुछ नमूना रूबी कोड है जो सरणी के प्रत्येक तत्व को प्रिंट करता है

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

ऐरे के प्रत्येक विधि कार्यान्वयन को कॉलर ('एक्स एक्स') पर नियंत्रित करता है जो सरणी के प्रत्येक तत्व को एक्स के रूप में अच्छी तरह से प्रस्तुत किया जाता है। कॉलर तब भी कर सकता है जो इसे एक्स के साथ करने की ज़रूरत है।

हालांकि, नेट यहाँ सभी तरह से नहीं जाता है .. सी # में आईनेमेरेबल के साथ युग्मित उपज है, जिस तरह से आप कॉलर में फोरैच लूप लिखने के लिए मजबूर कर रहे हैं जैसा कि मेंडेल की प्रतिक्रिया में देखा गया है। थोड़ा कम सुरुचिपूर्ण।

//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]; 
}

उपज कीवर्ड वास्तव में यहां बहुत कुछ करता है। फ़ंक्शन एक ऑब्जेक्ट देता है जो IENumerable इंटरफ़ेस लागू करता है। यदि एक कॉलिंग फ़ंक्शन इस ऑब्जेक्ट पर फ़ोरैच-इन शुरू करता है तो फ़ंक्शन को "उपज" तक दोबारा बुलाया जाता है। यह सी # 2.0 में पेश सिंथैक्टिक चीनी है। पिछले संस्करणों में आपको इस तरह की चीजें करने के लिए अपनी खुद की आईन्यूमेरेबल और आईन्यूमेरेटर ऑब्जेक्ट्स बनाना था।

इस तरह के कोड को समझने का सबसे आसान तरीका उदाहरण में टाइप करना है, कुछ ब्रेकपॉइंट्स सेट करें और देखें कि क्या होता है।

उदाहरण के लिए इसके माध्यम से कदम उठाने का प्रयास करें:

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

जब आप उदाहरण के माध्यम से कदम उठाते हैं तो आपको इंटेगर्स () रिटर्न पर पहला कॉल मिलेगा। दूसरा कॉल 2 देता है और लाइन "उपज रिटर्न 1" फिर से निष्पादित नहीं होती है।

यहां एक वास्तविक जीवन उदाहरण है

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

पहली नजर में, उपज वापसी एक आईएनयूमेरेबल लौटने के लिए एक .NET चीनी है।

उपज के बिना, संग्रह के सभी आइटम एक ही समय में बनाए जाते हैं:

class SomeData
{
    public SomeData() { }

    static public IEnumerable<SomeData> CreateSomeDatas()
    {
        return new List<SomeData> {
            new SomeData(), 
            new SomeData(), 
            new SomeData()
        };
    }
}

उपज का उपयोग करके वही कोड, यह आइटम द्वारा आइटम लौटाता है:

class SomeData
{
    public SomeData() { }

    static public IEnumerable<SomeData> CreateSomeDatas()
    {
        yield return new SomeData();
        yield return new SomeData();
        yield return new SomeData();
    }
}

उपज का उपयोग करने का लाभ यह है कि यदि आपके डेटा का उपभोग करने वाले फ़ंक्शन को संग्रह के पहले आइटम की आवश्यकता होती है, तो शेष आइटम नहीं बनाए जाएंगे।

उपज ऑपरेटर वस्तुओं की सृजन की मांग करता है क्योंकि इसकी मांग की जाती है। इसका उपयोग करने का यह एक अच्छा कारण है।


अगर मैं इसे सही ढंग से समझता हूं, तो यहां मैं उपज के साथ IENumerable लागू करने वाले फ़ंक्शन के परिप्रेक्ष्य से इसे कैसे वाक्यांश दूंगा।

  • यहां एक है।
  • अगर आपको किसी और की ज़रूरत है तो फिर से कॉल करें।
  • मुझे याद होगा कि मैंने आपको पहले ही क्या दिया है।
  • मुझे केवल तभी पता चलेगा जब मैं आपको दोबारा फोन कर सकता हूं।

यह आपके ऑब्जेक्ट के लिए एक गणना करने के लिए एक बहुत ही सरल और आसान तरीका है। कंपाइलर एक वर्ग बनाता है जो आपकी विधि को लपेटता है और यह लागू करता है, इस मामले में, Inumerable <object>। उपज कीवर्ड के बिना, आपको एक ऑब्जेक्ट बनाना होगा जो IENumerable <object> लागू करता है।


सहजता से, कीवर्ड इसे छोड़ दिए बिना फ़ंक्शन से एक मान देता है, यानी आपके कोड उदाहरण में यह वर्तमान item मान देता है और फिर लूप को फिर से शुरू करता है। अधिक औपचारिक रूप से, यह एक इटरेटर के लिए कोड उत्पन्न करने के लिए संकलक द्वारा उपयोग किया जाता है। इटरेटर ऐसे कार्य होते हैं जो IEnumerable ऑब्जेक्ट्स लौटाते हैं। MSDN बारे में उनके बारे में कई articles हैं।


एक सूची या सरणी कार्यान्वयन तुरंत सभी वस्तुओं को लोड करता है जबकि उपज कार्यान्वयन एक स्थगित निष्पादन समाधान प्रदान करता है।

व्यावहारिक रूप से, आवेदन की संसाधन खपत को कम करने के लिए आवश्यक न्यूनतम कार्य करने के लिए अक्सर वांछनीय होता है।

उदाहरण के लिए, हमारे पास एक ऐसा एप्लिकेशन हो सकता है जो डेटाबेस से लाखों रिकॉर्ड संसाधित करता हो। जब हम एक स्थगित निष्पादन पुल-आधारित मॉडल में IENumerable का उपयोग करते हैं तो निम्न लाभ प्राप्त किए जा सकते हैं:

  • स्केलेबिलिटी, विश्वसनीयता और भविष्यवाणी की संभावना में सुधार होने की संभावना है क्योंकि रिकॉर्ड्स की संख्या एप्लिकेशन की संसाधन आवश्यकताओं को महत्वपूर्ण रूप से प्रभावित नहीं करती है।
  • प्रदर्शन और प्रतिक्रिया में सुधार होने की संभावना है क्योंकि पूरे संग्रह को पहले लोड होने की प्रतीक्षा करने के बजाय प्रसंस्करण तुरंत शुरू हो सकता है।
  • पुनर्प्राप्ति और उपयोग में सुधार होने की संभावना है क्योंकि एप्लिकेशन को रोका जा सकता है, शुरू किया जा सकता है, बाधित हो सकता है या असफल हो सकता है। प्रगति पर केवल आइटम ही खोले जाएंगे, जो डेटा के पूर्व-फ़ेचिंग की तुलना में खो जाएंगे, जहां केवल परिणामों के एक हिस्से का उपयोग किया जाता था।
  • उन वातावरणों में निरंतर प्रसंस्करण संभव है जहां निरंतर वर्कलोड स्ट्रीम जोड़े जाते हैं।

उपज का उपयोग करने की तुलना में सूची जैसे पहले संग्रह बनाने के बीच तुलना की तुलना यहां दी गई है।

सूची उदाहरण

    public class ContactListStore : IStore<ContactModel>
    {
        public IEnumerable<ContactModel> GetEnumerator()
        {
            var contacts = new List<ContactModel>();
            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();
    }

कंसोल आउटपुट
ContactListStore: संपर्क 1 बनाना
ContactListStore: संपर्क 2 बनाना
ContactListStore: संपर्क 3 बनाना
संग्रह के माध्यम से पुन: प्रयास करने के लिए तैयार है।

नोट: पूरे संग्रह को सूची में एक आइटम के बिना भी स्मृति में लोड किया गया था

उपज उदाहरण

public class ContactYieldStore : IStore<ContactModel>
{
    public IEnumerable<ContactModel> 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();
}

कंसोल आउटपुट
संग्रह के माध्यम से पुन: प्रयास करने के लिए तैयार है।

नोट: संग्रह बिल्कुल निष्पादित नहीं किया गया था। यह IEnumerable की "स्थगित निष्पादन" प्रकृति के कारण है। किसी आइटम का निर्माण केवल तभी होता है जब यह वास्तव में आवश्यक हो।

जब हम संग्रह में पहला संपर्क प्राप्त करते हैं तो चलो संग्रह को फिर से कॉल करें और व्यवहार को उलट दें।

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

कंसोल आउटपुट
संग्रह के माध्यम से पुन: प्रयास करने के लिए तैयार है
ContactYieldStore: संपर्क 1 बनाना
हैलो बॉब

अच्छा! केवल पहला संपर्क तब बनाया गया जब ग्राहक ने संग्रह से आइटम को "खींच लिया"।


यह गणनात्मक अनुक्रम का उत्पादन कर रहा है। यह वास्तव में स्थानीय IENumerable अनुक्रम बना रहा है और इसे एक विधि परिणाम के रूप में वापस कर रहा है


इस link का एक साधारण उदाहरण है

यहां तक ​​कि सरल उदाहरण भी हैं

public static IEnumerable<int> testYieldb()
{
    for(int i=0;i<3;i++) yield return 4;
}

ध्यान दें कि उपज वापसी विधि से वापस नहीं आ जाएगी। yield return बाद भी आप एक WriteLine रेखा डाल सकते yield return

उपर्युक्त 4 इंट्स 4,4,4,4 का आईन्यूमेरेबल बनाता है

यहां एक WriteLine साथ। सूची में 4 जोड़ देंगे, एबीसी प्रिंट करें, फिर सूची में 4 जोड़ें, फिर विधि को पूरा करें और वास्तव में विधि से वापस लौटें (विधि पूरी होने के बाद, जैसा कि बिना किसी वापसी के प्रक्रिया के साथ होता है)। लेकिन इसमें एक मूल्य होगा, int की एक IEnumerable सूची, जो इसे पूरा होने पर लौटती है।

public static IEnumerable<int> testYieldb()
{
    yield return 4;
    console.WriteLine("abc");
    yield return 4;
}

ध्यान दें कि जब आप उपज का उपयोग करते हैं, तो आप जो भी लौट रहे हैं वह फ़ंक्शन के समान प्रकार का नहीं है। यह IEnumerable सूची के भीतर एक तत्व के प्रकार का है।

आप IEnumerable रूप में विधि के रिटर्न प्रकार के साथ उपज का उपयोग करते हैं। यदि विधि का रिटर्न प्रकार int या List<int> और आप yield उपयोग yield , तो यह संकलित नहीं होगा। आप उपज के बिना IEnumerable विधि रिटर्न प्रकार का उपयोग कर सकते हैं लेकिन ऐसा लगता है कि आप IEnumerable विधि रिटर्न प्रकार के बिना उपज का उपयोग नहीं कर सकते हैं।

और इसे निष्पादित करने के लिए आपको इसे एक विशेष तरीके से कॉल करना होगा।

static void Main(string[] args)
{
    testA();
    Console.Write("try again. the above won't execute any of the function!\n");

    foreach (var x in testA()) { }


    Console.ReadLine();
}



// static List<int> testA()
static IEnumerable<int> testA()
{
    Console.WriteLine("asdfa");
    yield return 1;
    Console.WriteLine("asdf");
}

yield return का उपयोग गणक के साथ किया जाता है। उपज कथन के प्रत्येक कॉल पर, कॉलर को नियंत्रण वापस कर दिया जाता है लेकिन यह सुनिश्चित करता है कि कैली का राज्य बनाए रखा जाए। इसके कारण, जब कॉलर अगले तत्व की गणना करता है, तो यह yield कथन के तुरंत बाद बॉल विधि में बयान विधि में निष्पादन जारी रखता है।

आइए इसे एक उदाहरण के साथ समझने की कोशिश करें। इस उदाहरण में, प्रत्येक पंक्ति के अनुरूप मैंने आदेश का उल्लेख किया है जिसमें निष्पादन बहता है।

static void Main(string[] args)
{
    foreach (int fib in Fibs(6))//1, 5
    {
        Console.WriteLine(fib + " ");//4, 10
    }            
}

static IEnumerable<int> Fibs(int fibCount)
{
    for (int i = 0, prevFib = 0, currFib = 1; i < fibCount; i++)//2
    {
        yield return prevFib;//3, 9
        int newFib = prevFib + currFib;//6
        prevFib = currFib;//7
        currFib = newFib;//8
    }
}

इसके अलावा, राज्य प्रत्येक गणना के लिए बनाए रखा जाता है। मान लीजिए, मेरे पास Fibs() विधि के लिए एक और कॉल है, तो इसके लिए राज्य रीसेट हो जाएगा।


Enum से और उसके लिए डालने के विभिन्न तरीके

enum orientation : byte
{
 north = 1,
 south = 2,
 east = 3,
 west = 4
}

class Program
{
  static void Main(string[] args)
  {
    orientation myDirection = orientation.north;
    Console.WriteLine(“myDirection = {0}”, myDirection); //output myDirection =north
    Console.WriteLine((byte)myDirection); //output 1

    string strDir = Convert.ToString(myDirection);
        Console.WriteLine(strDir); //output north

    string myString = “north”; //to convert string to Enum
    myDirection = (orientation)Enum.Parse(typeof(orientation),myString);


 }
}




c# yield