C #: Iterator vs function IEnumerable को वापस करता है

Oct 15 2020

मान लें कि दो तरीके हैं:

IEnumerable<int> DoSomething1();
IEnumerable<int> DoSomething2();

मेरी वस्तु की स्थिति को संशोधित करें। मुझे नहीं पता कि फ़ंक्शन yieldअंदर उपयोग करता है या सिर्फ एक रिटर्न देता है List<int>।

और फिर मैं आउटपुट लेना चाहूंगा और दो अन्य कार्यों को पास करूंगा:

void SendToUser(IEnumerable<int> values);
void PrintOut(IEnumerable<int> values);

फिर बस फ़ंक्शन इंटरफ़ेस पर आधारित ( DoSomethingX) मैं यह नहीं कह सकता कि यह एक वैध ऑपरेशन है या नहीं:

var values = DoSomethingX();
SendToUser(values);
PrintOut(values)

क्योंकि इटरेटर के मामले में यह DoSomethingXदो बार कॉल करने का परिणाम होगा ।

क्या यह किसी प्रकार की असंगतता है या मैं IEnumerableगलत तरीके से itter / का उपयोग कर रहा हूँ ? समस्या कहाँ हे?

जवाब

4 JohnathanBarclay Oct 15 2020 at 19:13

यदि कोई विधि वापस आती है, IEnumerableतो आपको केवल इस तथ्य पर भरोसा करना चाहिए कि यह चलने योग्य है, इससे अधिक कुछ नहीं, क्योंकि उस पद्धति का कार्यान्वयन परिवर्तन के अधीन है।

यदि आपके पास विधि पर नियंत्रण है और जानते हैं कि उपभोक्ताओं को अधिक विशिष्ट प्रकार की आवश्यकता होती है, तो अधिक विशिष्ट प्रकार लौटाएं।

यदि आपके पास नियंत्रण नहीं है और सूची व्यवहार को लागू करने की आवश्यकता है, तो आप हमेशा IEnumerableसूची में बदल सकते हैं :

var values = DoSomethingX().ToList();
SendToUser(values);
PrintOut(values);
1 apocalypse Oct 15 2020 at 19:50

CQS (कमांड क्वेरी पृथक्करण) के बारे में पढ़ें: विकिपीडिया

संक्षेप में, 2 प्रकार की विधियाँ हैं:

  1. आदेश, जैसे void DoSomething(string data)- वे आपके उदाहरण की स्थिति बदलते हैं
  2. प्रश्न, जैसे IEnumerable<Person> GetPeople(Filter filter)- जो राज्य नहीं बदलता है, वे सिर्फ कुछ डेटा लौटाते हैं

कभी-कभी आदेश मान वापस कर सकते हैं, अर्थात PersonID CreatePerson(...);

इसलिए यदि आप अपना कोड रिफलेक्टर करते हैं:

void DoSomething1();
void DoSomething2();
IEnumerable<int> GetData();

यह आपकी समस्या का समाधान करेगा।

IEnumerableप्रकार सिर्फ एक अंतरफलक है कि आप कुछ तत्वों से अधिक चीज़ों को दोहरा सकते है। आपको इस बात का अंदाजा नहीं है कि ठोस कार्यान्वयन के अंदर क्या है।
आमतौर पर कार्यान्वयन का IEnumerableकोई दुष्प्रभाव नहीं होना चाहिए, अर्थात कुछ वस्तुओं की बदलती स्थिति।

यदि आप IEnumerableउस परिवर्तन स्थिति के साथ काम कर रहे हैं , तो आप .ToList()LINQ एक्सटेंशन का उपयोग करके इसे हमेशा भौतिक बना सकते हैं । तब आप इसे किसी भी विधि w / o से किसी भी अतिरिक्त दुष्प्रभाव के लिए पारित कर सकते हैं।

OlivierJacot-Descombes Oct 15 2020 at 20:11

असाइनमेंट var values = DoSomethingX();संग्रह या पुनरावृत्त की गणना नहीं करता है।

  1. यह वापस आ सकता है List<int>। इस मामले में सूची सौंपी गई है values। अधिक सटीक: इस सूची का संदर्भ।

  2. अगर DoSomethingXएक पुनरावृत्त विधि है, तो C # एक अनाम वर्ग के एक ऑब्जेक्ट IEnumerable<int>को एक राज्य मशीन के रूप में लागू करता है। इस वस्तु को सौंपा गया है values।

इसलिए इन दोनों के उपयोग में कोई अंतर नहीं है IEnumerable<int>। इससे कोई फर्क नहीं पड़ता कि यह संग्रह पर आधारित है या पुनरावृत्ति विधि पर। पुनरावृत्ति आम तौर पर एक के लिए-प्रत्येक पाश में शुरू होता है या जब की तरह एक LINQ विधि बुला ToListया ToArray।

आप मैन्युअल रूप से iterate कर सकते हैं। सबसे पहले आपको एन्यूमरेटर प्राप्त करना होगा:

IEnumerator<int> enumerator = values.GetEnumerator();

फिर इस एन्यूमरेटर के तरीकों को कॉल करें:

while (enumerator.MoveNext()) { // Enumeration starts here.
    int value = enumerator.Current;
    ...
}

जब आप पुनरावृति से अधिक IEnumerableया IEnumerable<T>दो बार, तो निश्चित रूप से अपने कोड दो बार चलाता है। यदि आपको लगता है कि यह समय लेने वाला हो सकता है, उदाहरण के लिए यदि इट्रेटर डेटाबेस या फाइल सिस्टम पर सवाल उठाता है, तो आपको .ToList()इसे दो बार कॉल करने से पहले कॉल करना चाहिए :

var records = QueryDatabaseReturnsIEnumerable().ToList();
SendToUser(records);
PrintOut(records);

दूसरी ओर, कॉल करने पर .ToList()जब गणना योग्य संग्रह पर आधारित होता है, तो आप एक अनावश्यक मेमोरी और समय लेने वाली कॉपी ऑपरेशन करते हैं।

आमतौर पर आप संदर्भ से कह सकते हैं, यह आवश्यक है या नहीं। अन्यथा सबसे अच्छा आप कर सकते हैं, अन्य इंटरफेस के लिए परीक्षण करना है:

IEnumerable<int> values = DoSomethingX();
if (!(values is IList<int>) && !(values is ICollection<int>)) {
    values = values.ToList();
}
SendToUser(values);
PrintOut(values);

लेकिन मुझे संदेह है कि यह एक अच्छा अभ्यास है। उनके कार्यान्वयन के बारे में चिंता किए बिना इंटरफेस का सेवन किया जाना चाहिए। ऐसा करना उनके उद्देश्य को धता बताता है।