दो मान लौटाते हुए, टपल बनाम 'आउट' बनाम 'स्ट्रक्चर'


86

एक फ़ंक्शन पर विचार करें जो दो मान लौटाता है। हम लिख सकते है:

// Using out:
string MyFunction(string input, out int count)

// Using Tuple class:
Tuple<string, int> MyFunction(string input)

// Using struct:
MyStruct MyFunction(string input)

कौन सा सबसे अच्छा अभ्यास है और क्यों?


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

@ एरिक: आप सही हैं। मेरा मतलब अपरिवर्तनीय प्रकारों से था।
ज़ाक्रॉन

और एक वर्ग के साथ क्या गलत है?
लुकाज़ मैडन

1
@ लुकास: कुछ भी नहीं, लेकिन निश्चित रूप से यह सर्वोत्तम प्रथाओं में नहीं है। यह एक हल्के मूल्य (<16 KB) है और अगर मैं एक कस्टम कोड जोड़ने वाला, मैं के साथ जाना होगा structके रूप में Ericउल्लेख किया है।
ज़ैकॉन

1
मैं केवल तभी उपयोग करूंगा जब आपको यह निर्धारित करने के लिए रिटर्न वैल्यू की आवश्यकता होगी कि क्या आपको रिटर्न डेटा को प्रोसेसपर्स में प्रयोग करना चाहिए, अन्यथा आपको हमेशा एक स्ट्रक्चर्ड ऑब्जेक्ट वापस करना चाहिए, जैसे कि स्ट्रक्चर्ड ऑब्जेक्ट वैल्यू टाइप होना चाहिए या एक संदर्भ टाइप इस बात पर निर्भर करता है कि आप डेटा का किस अतिरिक्त उपयोग करते हैं
माइक

जवाबों:


93

वे प्रत्येक अपने पेशेवरों और विपक्ष हैं।

आउट पैरामीटर तेज़ और सस्ते हैं, लेकिन इसके लिए आवश्यक है कि आप एक चर में पास करें, और म्यूटेशन पर भरोसा करें। LINQ के साथ आउट पैरामीटर को सही ढंग से उपयोग करना लगभग असंभव है।

ट्यूपल्स कचरा संग्रह दबाव बनाते हैं और संयुक्त राष्ट्र के स्व-दस्तावेजीकरण होते हैं। "आइटम 1" बहुत वर्णनात्मक नहीं है।

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

मैं कस्टम संरचना समाधान के लिए इच्छुक हो जाएगा अन्य सभी चीजें समान हैं। हालांकि यह भी बेहतर है कि एक ऐसा फंक्शन बनाया जाए जो केवल एक मूल्य लौटाए । आप पहले स्थान पर दो मान क्यों लौटा रहे हैं?

अद्यतन: ध्यान दें कि सी # 7 में ट्यूपल, जो इस लेख को लिखे जाने के छह साल बाद भेज दिया गया है, मूल्य प्रकार हैं और इसलिए संग्रह दबाव बनाने की संभावना कम है।


2
दो प्रकारों को वापस करना अक्सर विकल्प प्रकार या एडीटी नहीं होने के लिए एक विकल्प है।
एंटोन टायखी

2
अन्य भाषाओं के साथ अपने अनुभव से, मैं कहूंगा कि आम तौर पर टुपल्स का उपयोग वस्तुओं के त्वरित और गंदे समूहन के लिए किया जाता है। यह आमतौर पर एक वर्ग या संरचना बनाने के लिए बेहतर है, क्योंकि यह आपको प्रत्येक आइटम का नाम देने की अनुमति देता है। टुपल्स का उपयोग करते समय प्रत्येक मूल्य का अर्थ निर्धारित करना कठिन हो सकता है। लेकिन यह आपको क्लास / स्ट्रक्चर बनाने के लिए समय लेने से बचाता है जो कि ओवरक्लिल हो सकता है यदि उक्त क्लास / स्ट्रक्चर अन्यत्र उपयोग नहीं किया जाएगा।
केविन कैथार्ट

23
@Xaqron: यदि आप पाते हैं कि "टाइमआउट के साथ डेटा" का विचार आपके कार्यक्रम में सामान्य है, तो आप एक सामान्य प्रकार "टाइमलीस्ड <टी>" बनाने पर विचार कर सकते हैं, ताकि आप अपनी विधि को एक टाइमलाइन सी <string> या TimeLimited लौटा सकें। <उड़ी> या जो भी हो। TimeLimited <T> वर्ग में सहायक विधियाँ हो सकती हैं जो आपको बताती हैं कि "हमें कितने समय के लिए छोड़ दिया गया है?" या "क्या यह समाप्त हो गया है?" जो कुछ भी। टाइप सिस्टम में इस तरह के दिलचस्प शब्दार्थ को पकड़ने की कोशिश करें।
एरिक लिपर्ट

3
बिल्कुल, मैं सार्वजनिक इंटरफ़ेस के हिस्से के रूप में टपल का उपयोग कभी नहीं करूंगा। लेकिन यहां तक ​​कि 'निजी' कोड के लिए, मुझे टपल का उपयोग करने के बजाय एक उचित प्रकार से बहुत अधिक पठनीयता मिलती है (विशेष रूप से ऑटो गुणों के साथ एक निजी आंतरिक प्रकार बनाना कितना आसान है)।
SolutionYogi

2
संग्रह दबाव का क्या अर्थ है?
रोल

25

पिछले उत्तरों में जोड़ते हुए, C # 7 वैल्यू टाइप ट्यूपल्स लाता है, इसके विपरीत System.Tupleएक संदर्भ प्रकार है और बेहतर शब्दार्थ भी प्रस्तुत करता है।

आप अभी भी उन्हें अनाम नहीं छोड़ सकते हैं और .Item*वाक्यविन्यास का उपयोग कर सकते हैं:

(string, string, int) getPerson()
{
    return ("John", "Doe", 42);
}

var person = getPerson();
person.Item1; //John
person.Item2; //Doe
person.Item3;   //42

लेकिन इस नई सुविधा के बारे में जो वास्तव में शक्तिशाली है वह टुपल्स नाम की क्षमता है। तो हम इस तरह से ऊपर फिर से लिख सकते हैं:

(string FirstName, string LastName, int Age) getPerson()
{
    return ("John", "Doe", 42);
}

var person = getPerson();
person.FirstName; //John
person.LastName; //Doe
person.Age;   //42

विनाशकारी भी समर्थित है:

(string firstName, string lastName, int age) = getPerson()


2
क्या मैं यह सोचने में सही हूं कि यह मूल रूप से हुड के तहत सदस्यों के रूप में संदर्भ के साथ एक संरचना है?
ऑस्टिन_एंडर्सन सेप

4
क्या हमें पता है कि उस प्रदर्शन का उपयोग परमों के उपयोग से कैसे किया जाता है?
SpaceMonkey

20

मुझे लगता है कि उत्तर इस बात पर निर्भर करता है कि फ़ंक्शन क्या कर रहा है, और दो मूल्यों के बीच संबंध क्या है।

उदाहरण के लिए, TryParseतरीके outपार्स किए गए मान को स्वीकार करने के लिए एक पैरामीटर लेते हैं , और boolयह इंगित करने के लिए कि पार्स सफल हुआ या नहीं। दो मूल्य वास्तव में एक साथ नहीं हैं, इसलिए, शब्दार्थ, यह अधिक समझ में आता है, और कोड का इरादा पढ़ने में आसान है, outपैरामीटर का उपयोग करने के लिए ।

यदि, हालांकि, आपका फ़ंक्शन स्क्रीन पर किसी वस्तु के X / Y निर्देशांक को लौटाता है, तो दो मूल्य शब्दार्थ से संबंधित हैं और इसका उपयोग करना बेहतर होगा struct

मैं व्यक्तिगत रूप से किसी tupleभी चीज के लिए उपयोग करने से बचना चाहूंगा जो सदस्यों को पुनः प्राप्त करने के लिए अजीब सिंटैक्स के बाहरी कोड becuase को दिखाई देगा।


शब्दार्थ के लिए +1। जब हम outपैरामीटर छोड़ सकते हैं तो आपका उत्तर अधिक उपयुक्त सफेद संदर्भ प्रकार होता है null। वहाँ कुछ अशक्त अपरिवर्तनीय प्रकार हैं।
ज़ैकॉन

3
वास्तव में, ट्राइएपर्स में दो मान बहुत अधिक एक साथ होते हैं, एक रिटर्न मान के रूप में और दूसरा बायरफ पैरामीटर के रूप में निहित होने की तुलना में बहुत अधिक है। कई मायनों में, वापसी करने के लिए तार्किक बात एक अशक्त प्रकार होगी। ऐसे कुछ मामले हैं जहाँ TryParse पैटर्न अच्छी तरह से काम करता है, और कुछ जहाँ यह दर्द होता है (यह अच्छा है कि इसका उपयोग "if" स्टेटमेंट में किया जा सकता है, लेकिन ऐसे कई मामले हैं जहाँ एक अशक्त मान वापस करना या डिफ़ॉल्ट मान निर्दिष्ट करने में सक्षम होना अधिक सुविधाजनक होगा)।
सुपरकैट

@supercat मैं andrew से सहमत होगा, वे एक साथ नहीं हैं। हालांकि वे संबंधित हैं वापसी आपको बताती है कि क्या आपको मूल्य के साथ परेशान करने की आवश्यकता है, न कि कुछ ऐसी चीज़ों के साथ, जिन्हें अग्रानुक्रम में संसाधित करने की आवश्यकता है। इसलिए जब आपने रिटर्न को संसाधित किया है, तो आउट वैल्यू से संबंधित किसी अन्य प्रोसेसिंग के लिए इसकी आवश्यकता नहीं है, यह एक KeyValuePair को एक शब्दकोश से वापस करने की तुलना में अलग है जहां एक स्पष्ट और कुंजी और मूल्य के बीच लिंक पर जा रहा है। हालांकि मैं सहमत हूँ कि यदि अशक्त प्रकार। नेट 1.1 में हैं, तो उन्होंने संभवतः उन्हें उपयोग किया होगा क्योंकि नल का कोई मूल्य नहीं होने का एक उचित तरीका होगा
माइक

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

@ मायके: क्योंकि सहसंयोजक तरीके हैं और ढांचे के भीतर समर्थित नहीं हैं, एकमात्र tryपैटर्न जो सहसंयोजक इंटरफेस के साथ काम करता है T TryGetValue(whatever, out bool success); कि दृष्टिकोण की अनुमति होता इंटरफेस IReadableMap<in TKey, out TValue> : IReadableMap<out TValue>है, और जो के उदाहरण मैप करने के लिए चाहता है कोड जाने Animalके उदाहरण के लिए Carस्वीकार करने के लिए एक Dictionary<Cat, ToyotaCar>[का उपयोग कर TryGetValue<TKey>(TKey key, out bool success)। यदि पैरामीटर के TValueरूप में उपयोग किया जाता है तो ऐसा कोई भी विचरण संभव नहीं है ref
सुपरकैट

2

मैं आउट पैरामीटर का उपयोग करने के दृष्टिकोण के साथ जाऊंगा क्योंकि दूसरे दृष्टिकोण में आपको टपल क्लास बनाने और ऑब्जेक्ट करने की आवश्यकता होगी और फिर इसमें वैल्यू ऐड किया जाएगा, जो मुझे लगता है कि आउट पैरामीटर में वैल्यू वापस करने की तुलना में एक महंगा ऑपरेशन है। यद्यपि यदि आप टपल क्लास में कई मूल्यों को वापस करना चाहते हैं (जो कि केवल एक पैरामीटर को वापस करने से पूरा नहीं किया जा सकता है) तो मैं दूसरे दृष्टिकोण के लिए जाऊंगा।


मैं इससे सहमत हूं out। इसके अतिरिक्त एक paramsकीवर्ड है जिसका मैंने प्रश्न को सीधा रखने के लिए उल्लेख नहीं किया है।
एक्सकॉन

2

आपने एक और विकल्प का उल्लेख नहीं किया है, जिसमें संरचना के बजाय एक कस्टम वर्ग है। यदि डेटा में इससे संबंधित शब्दार्थक शब्द हैं, जिन्हें फ़ंक्शंस द्वारा संचालित किया जा सकता है, या उदाहरण का आकार काफी बड़ा है (> अंगूठे के नियम के रूप में 16 बाइट्स), तो एक कस्टम वर्ग को प्राथमिकता दी जा सकती है। सार्वजनिक एपीआई में "आउट" का उपयोग इंगित करने के लिए इसके संघ के कारण और संदर्भ प्रकार के काम की समझ की आवश्यकता के कारण उपयोग नहीं किया जाता है।

https://msdn.microsoft.com/en-us/library/ms182131.aspx

ट्यूल आंतरिक उपयोग के लिए अच्छा है, लेकिन सार्वजनिक एपीआई में इसका उपयोग अजीब है। इसलिए, मेरा वोट सार्वजनिक एपीआई के लिए संरचना और वर्ग के बीच है।


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

0

कोई "सर्वश्रेष्ठ अभ्यास" नहीं है। यह वह है जो आप के साथ सहज हैं और आपकी स्थिति में सबसे अच्छा क्या काम करता है। जब तक आप इसके अनुरूप होते हैं, आपके द्वारा पोस्ट किए गए किसी भी समाधान के साथ कोई समस्या नहीं है।


3
बेशक वे सभी काम करते हैं। यदि कोई तकनीकी लाभ नहीं है, तो मैं अभी भी यह जानने के लिए उत्सुक हूं कि ज्यादातर विशेषज्ञों द्वारा क्या उपयोग किया जाता है।
ज़ैकॉन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.