2012-03-09 42 views
17

हम एक ही विधि में रिटर्न और उपज रिटर्न दोनों का उपयोग क्यों नहीं कर सकते?एक ही विधि में "वापसी" और "उपज रिटर्न" का उपयोग क्यों नहीं किया जा सकता है?

उदाहरण के लिए, हम GetIntegers1 और GetIntegers2 नीचे प्राप्त कर सकते हैं, लेकिन GetIntegers3 नहीं।

public IEnumerable<int> GetIntegers1() 
{ 
    return new[] { 4, 5, 6 }; 
} 

public IEnumerable<int> GetIntegers2() 
{ 
    yield return 1; 
    yield return 2; 
    yield return 3; 
} 

public IEnumerable<int> GetIntegers3() 
{ 
    if (someCondition) 
    { 
    return new[] {4, 5, 6}; // compiler error 
    } 
    else 
    { 
    yield return 1; 
    yield return 2; 
    yield return 3; 
    } 
} 
+11

एक सेकंड प्रतीक्षा करें, जोन स्कीट अब आ जाएगा। – Juvanis

+0

मैं इसे जोड़ दूंगा यदि आपको वास्तव में इसकी आवश्यकता है, तो आप एक GetIngegers4 बना सकते हैं जो किसी शर्त के आधार पर GetIntegers1 या GetIntegers2 को कॉल करता है। – xanatos

+0

यह शायद स्पष्ट है, लेकिन ऐसे मामलों में आप हमेशा अपने संग्रह को अनलॉक कर सकते हैं और उपज आइटम वापस कर सकते हैं: foreach (नया आइटम [] {4,5,6}) उपज वापसी आइटम; – Foo42

उत्तर

16

return उत्सुक है। यह एक बार में पूरे परिणाम देता है। yield return एक गणक बनाता है। जब आप yield return का उपयोग करते हैं तो दृश्यों के पीछे सी # कंपाइलर गणनाकर्ता के लिए आवश्यक कक्षा को उत्सर्जित करता है। संकलक if (someCondition) जैसे रनटाइम स्थितियों की तलाश नहीं करता है यह निर्धारित करते समय कि यह एक गणना के लिए कोड को उत्सर्जित करना चाहिए या एक विधि है जो एक साधारण सरणी देता है। यह पता लगाता है कि आपकी विधि में आप दोनों का उपयोग कर रहे हैं जो संभव नहीं है क्योंकि वह एक गणक के लिए कोड उत्सर्जित नहीं कर सकता है और साथ ही विधि एक सामान्य सरणी को वापस कर सकती है और यह सब एक ही विधि के लिए होती है।

+0

जब मैं कोड डीबग करने का प्रयास करता हूं, तो मैं देख सकता हूं कि यह पुनरावृत्ति में कोड की सभी पंक्तियों की यात्रा करता है। फिर हम कैसे कह सकते हैं कि यह आंतरिक रूप से गणनाकर्ता बनाता है और इसे केवल एक बार लौटाता है ... – Karan

7

कंपाइलर yield कथन (वापसी या ब्रेक) के साथ किसी भी तरीके को फिर से लिखता है। यह वर्तमान में उन तरीकों को संभाल नहीं सकता है जो yield हो सकता है या नहीं।

मैं जॉन स्कीट के C# in Depth के अध्याय 6 के पढ़ने के अनुशंसा करता हूं, जिसमें से अध्याय 6 मुफ्त में उपलब्ध है - इसमें इटेटरेटर ब्लॉक काफी अच्छी तरह से शामिल हैं।

मुझे कोई कारण नहीं दिख रहा है कि यह सी # कंपाइलर के भविष्य के संस्करणों में क्यों संभव नहीं होगा। अन्य .Net भाषाएं 'उपज से' ऑपरेटर (See F# yield!) के रूप में समान कुछ का समर्थन करती हैं। अगर इस तरह के एक ऑपरेटर सी # में ही अस्तित्व में यह आप के रूप में अपने कोड लिखने की अनुमति होगी:

public IEnumerable<int> GetIntegers() 
{ 
    if (someCondition) 
    { 
    yield! return new[] {4, 5, 6}; 
    } 
    else 
    { 
    yield return 1; 
    yield return 2; 
    yield return 3; 
    } 
} 
10

नहीं, तुम ऐसा नहीं कर सकते - एक iterator ब्लॉक (एक yield के साथ कुछ) नियमित उपयोग नहीं कर सकते (गैर उपज) return

public IEnumerable<int> GetIntegers3() 
{ 
    if (someCondition) 
    { 
    return new[] {4, 5, 6}; // compiler error 
    } 
    else 
    { 
    return GetIntegers3Deferred(); 
    } 
} 
private IEnumerable<int> GetIntegers3Deferred() 
{ 
    yield return 1; 
    yield return 2; 
    yield return 3; 
} 

या के बाद से इस विशेष मामले दोनों पहले से ही अन्य 2 तरीकों में मौजूद है के लिए कोड में: इसके बजाय, आप 2 तरीकों का उपयोग करने की आवश्यकता है

public IEnumerable<int> GetIntegers3() 
{ 
    return (someCondition) ? GetIntegers1() : GetIntegers2(); 
} 
3

सैद्धांतिक रूप से मैं वहाँ लगता है कोई कारण नहीं है क्यों वापसी और उपज वापसी नहीं मिलाया जा सकता:

var myEnumerable = blabla(); 
foreach (var m in myEnumerable) 
    yield return m; 
yield break; 
: यह वाक्य रचना में किसी भी return (blabla()); वाक्य को बदलने पहले करने के लिए संकलक के लिए एक आसान बात नहीं होगी 10

और फिर जारी रखें (पूरी विधि को बदलने के लिए ... जो भी वे इसे बदलते हैं; एक आंतरिक गुमनाम IEnumerator वर्ग ?!)

तो क्यों वे इसे लागू करने में नहीं चुना था, यहाँ दो अनुमान हैं:

  • उन्होंने फैसला किया कि हो सकता है उन दोनों वापसी के लिए के लिए यह भ्रामक हो सकता है और एक बार में उपज वापसी,

  • पूरे गणित को वापस करना तेज़ और सस्ता है लेकिन उत्सुक भी है; उपज रिटर्न के माध्यम से इमारत थोड़ी अधिक महंगी होती है (विशेष रूप से यदि रिकर्सिवली कहा जाता है, तो एरिक लिपर्ट की बाइनरी पेड़ों में ट्रैवर्सल के लिए चेतावनी रिटर्न स्टेटमेंट्स के साथ चेतावनी देखें: https://stackoverflow.com/a/3970171/671084 उदाहरण के लिए) लेकिन आलसी। तो एक उपयोगकर्ता आमतौर पर इन्हें मिश्रण नहीं करना चाहता: यदि आपको आलस्य की आवश्यकता नहीं है (यानी।आप पूरे अनुक्रम को जानते हैं) दक्षता दंड का सामना न करें, केवल एक सामान्य विधि का उपयोग करें। हो सकता है कि वे उपयोगकर्ता को इन पंक्तियों के साथ सोचने के लिए मजबूर करना चाहें।

दूसरी ओर, ऐसा लगता है कि ऐसी स्थितियां हैं जहां उपयोगकर्ता कुछ वाक्य रचनात्मक एक्सटेंशन से लाभ उठा सकता है; आप इस प्रश्न और उत्तर को एक उदाहरण के रूप में पढ़ना चाहेंगे (एक ही प्रश्न नहीं, लेकिन संभवतः एक समान उद्देश्य के साथ): Yield Return Many?

+0

यह वास्तव में "माइक्रोसॉफ्ट ने समर्थन करने का फैसला करने का कारण क्या हो सकता है ...", जो बेहतर होगा पहली जगह में सवाल। –

0

मुझे लगता है कि यह मुख्य कारण क्यों नहीं काम करता है क्योंकि यह इस तरह से डिजाइन कर रहा है अपेक्षाकृत कम नहीं है लेकिन अपेक्षाकृत कम लाभ के साथ एक ही समय में प्रदर्शन करने वाला कठिन होगा।

आपका कोड वास्तव में क्या करेगा? क्या यह सीधे सरणी वापस कर देगा, या यह इसके ऊपर फिर से होगा?

यह सीधे सरणी वापसी होगी, तो आप क्या शर्तों के तहत जटिल नियम लगता है करने के लिए होगा, return अनुमति है, क्योंकि returnyield return के बाद मतलब नहीं है। और आपको शायद यह तय करने के लिए जटिल कोड उत्पन्न करने की आवश्यकता होगी कि क्या विधि कस्टम इटरेटर या सरणी वापस कर देगी।

यदि आप संग्रह को पुन: सक्रिय करना चाहते हैं, तो शायद आप कुछ बेहतर कीवर्ड चाहते हैं। Something like yield foreach। वास्तव में इसे माना जाता था, लेकिन अंत में लागू नहीं किया गया था। मुझे लगता है कि मुझे मुख्य कारण पढ़ना याद रखना है कि यदि आपके पास कई नेस्टेड इटरेटर हैं तो इसे वास्तव में अच्छा प्रदर्शन करना वास्तव में कठिन होता है।

+1

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

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^