C # 7 में "कोशिश" विधि लिखने का सबसे सुरुचिपूर्ण तरीका क्या है?


21

मैं एक प्रकार का क्यू कार्यान्वयन लागू कर रहा हूं जिसमें एक TryDequeueविधि है जो विभिन्न .NET TryParseविधियों के समान एक पैटर्न का उपयोग करती है , जहां मैं बूलियन मान लौटाता हूं यदि कार्रवाई सफल हुई, और outवास्तविक समाप्त मान को वापस करने के लिए एक पैरामीटर का उपयोग करें ।

public bool TryDequeue(out Message message) => _innerQueue.TryDequeue(out message);

अब, outजब भी मैं कर सकता हूं मुझे परम से बचना पसंद है । C # 7 हमें उनके साथ काम करना आसान बनाने के लिए परिवर्तनीय विलंब प्रदान करता है, लेकिन मैं अभी भी एक उपयोगी उपकरण की तुलना में अधिक आवश्यक बुराईयों को अधिक मानता हूं।

इस विधि से मुझे जो व्यवहार चाहिए वह इस प्रकार है:

  • यदि किसी वस्तु को धोखा देना है, तो उसे लौटा दें।
  • यदि वहाँ कोई आइटम नहीं हैं (क्यू खाली है), कॉल करने वाले को उचित कार्य करने के लिए पर्याप्त जानकारी प्रदान करें।
  • यदि कोई आइटम नहीं बचा है, तो बस एक अशक्त वस्तु वापस न करें।
  • यदि कोई खाली कतार से हटने की कोशिश कर रहा हो तो अपवाद न फेंकें।

अभी, इस विधि का एक कॉलर लगभग हमेशा निम्न की तरह एक पैटर्न का उपयोग करेगा: (C # 7 बाहर चर वाक्यविन्यास का उपयोग करके):

if (myMessageQueue.TryDequeue(out Message dequeued))
    MyMessagingClass.SendMessage(dequeued)
else
    Console.WriteLine("No messages!"); // do other stuff

जो सबसे बुरा नहीं है, सब बताया गया है। लेकिन मैं मदद नहीं कर सकता, लेकिन लगता है कि ऐसा करने के अच्छे तरीके हो सकते हैं (मैं पूरी तरह से सहमत होना चाहता हूं कि ऐसा नहीं हो सकता)। मुझे नफरत है कि कैसे कॉल करने वाले को तोड़ना पड़ता है यह एक सशर्त के साथ प्रवाह होता है जब यह चाहता है कि एक मौजूद होने पर एक मूल्य प्राप्त हो।

कुछ अन्य पैटर्न जो इस "कोशिश" व्यवहार को पूरा करने के लिए मौजूद हैं?

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


9
एक Option<T>संरचना को परिभाषित करें और इसे वापस करें। वे bool Try(..., out data)कार्य एक घृणा हैं।
कोडइन्चौस

2
मैं भी ऐसा ही सोच रहा था ... शायद <टी>, विकल्प <टी> अगर कोई ओयूटी मापदंडों के प्रतिकूल है।
जॉन रेनोर

1
@FrustratedWithFormsDesigner अच्छी तरह से, मैं इतना "कोशिश" अन्य चीजों (सज़ा का स्वागत है) नहीं है, तो उनमें से बहुत सोचा था। मेरे पास ValueTuple वापस करने का विचार था लेकिन सबसे अच्छा मुझे नहीं लगता कि इसमें बहुत सुधार की पेशकश की गई थी।
एरिक सोनगार्ड

@CodesInChaos हम एक ही पृष्ठ पर हैं, इसीलिए मैं यहाँ हूँ! और मुझे यह विचार पसंद है। यदि आपके पास समय है, तो क्या आप एक उत्तर में कुछ और विवरण देना चाहेंगे ताकि मैं इसे स्वीकार कर सकूं?
एरिक सोन्डरगार्ड

जवाबों:


24

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

अतिरिक्त विशेषताओं में संबंधित स्थितियों में कार्रवाई करने के लिए IFPresent और IfNotPresent जैसी विधियां शामिल हो सकती हैं, और OrElse (जो कि डिफ़ॉल्ट मान का विकल्प देता है जब कोई मूल्य मौजूद नहीं है, लेकिन अन्यथा कोई op नहीं है), और इसी तरह।

आपका उदाहरण तब कुछ इस तरह दिख सकता है:

myMessageQueue.TryDeque()
    .IfPresent( dequeued => MyMessagingClass.SendMessage(dequeued))
    .IfNotPresent (() =>  Console.WriteLine("No messages!")

यह विकल्प (या हो सकता है) मोनड पैटर्न है, और यह अत्यंत उपयोगी है। मौजूदा कार्यान्वयन हैं (जैसे https://github.com/nlkl/Optional/blob/master/README.md ) लेकिन यह आपके लिए कठिन नहीं है।

(आप इस पैटर्न को विस्तारित करने की इच्छा कर सकते हैं ताकि आप त्रुटि के कारण का वर्णन वापस कर दें जब कि विधि विफल होने के बजाय कुछ भी न हो ... यह पूरी तरह से प्राप्त करने योग्य है और अक्सर इसे या तो मोनाड कहा जाता है, जैसा कि नाम से पता चलता है कि आप एक ही फ़्लैटमैप का उपयोग कर सकते हैं; पैटर्न उस मामले में भी काम करना आसान बनाता है,)


यह निश्चित रूप से एक अच्छा विकल्प है, सुझाव और आपके विचारों के लिए धन्यवाद। मैं वास्तव में यहां अधिक विचारों का पता लगाने के लिए देख रहा था।
एरिक सोल्डरगार्ड

2
के बारे में अच्छी बात यह है Option/ Maybeकि यह एक इकाई है (अगर, एक के रूप में लागू किया निश्चित रूप से), जिसका अर्थ है कि यह सुरक्षित रूप से, श्रृंखलित जा सकती है लिपटे हैं, unwrapped, और प्रसंस्कृत कभी सीधे विभिन्न मामलों को संभालने के लिए जरूरत के बिना है, और इस श्रृंखलन और LINQ Query Expressions से प्रोसेसिंग की जा सकती है।
जोर्ग डब्ल्यू मित्तग

3
वैसे, flatMap/ .NET में bindकहा जाता SelectManyहै।
जॉर्ग डब्ल्यू मित्तग

5
मुझे आश्चर्य है कि अगर एक अलग नाम चुनना बेहतर होगा, क्योंकि ऐसा करने से आप Try....NET (और संभावित रूप से भ्रामक बनाए रखने वाले) नामकरण सम्मेलनों को तोड़ रहे हैं ।
बॉब

@ थोबड़ा यह एक महान बिंदु है। मैं सहमत हूँ।
एरिक सोनगार्ड

12

दिए गए उत्तर अच्छे हैं और मैं उनमें से एक के साथ जाऊंगा। इस उत्तर को कुछ वैकल्पिक विचारों के साथ केवल कुछ कोनों में भरने के लिए समझें:

  • Messageबुलाया SomeMessageऔर के उपवर्ग बनाएं NoMessage। यदि कोई संदेश नहीं है, और यदि कोई संदेश है तो Dequeueअब वापस आ सकते हैं । अगर कैली को पता है कि वे किस मामले में हैं, तो वे आसानी से टाइप इंस्पेक्शन कर सकते हैं। अगर वे नहीं करते हैं, ठीक है, जब भी इसके किसी भी तरीके को बुलाया जाता है, तो बस कुछ भी नहीं करते हैं, और हे, वे जो भी मांगते हैं वह मिलता है।NoMessageSomeMessageNoMessage

  • उपरोक्त के समान, लेकिन Messageअंतर्निहित रूप से परिवर्तनीय bool(या कार्यान्वित operator true / operator false) करें। अब आप कह सकते हैं if (message)और क्या यह सच है कि यदि संदेश बुरा है और गलत है तो गलत है। (यह लगभग निश्चित रूप से एक बुरा विचार है, लेकिन मैं इसे पूर्णता के लिए शामिल करता हूं!)

  • C # 7 में ट्यूपल हैं। (bool, Message)टपल लौटा दो ।

  • Messageएक संरचनात्मक प्रकार बनाएं और वापस लौटें Message?


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

मेरा मतलब है, अगर आपका "बुरा विचार" एकता द्वारा उपयोग किया जाता है, तो हम इसका उपयोग क्यों नहीं कर सकते हैं?
आर्टुरो टॉरेस सांचेज़

@ ArturoTorresSánchez: आपका प्रश्न "किसी और ने वास्तव में खराब प्रोग्रामिंग अभ्यास का उपयोग किया है, इसलिए मैं क्यों नहीं कर सकता हूं?" प्रश्न असंगत है। कोई आपको किसी अन्य के समान खराब प्रोग्रामिंग प्रथाओं का उपयोग करने से नहीं रोक रहा है। तुम ठीक आगे बढ़ो। यह C # में अच्छा अभ्यास नहीं करेगा।
एरिक लिपर्ट

गाल में जीभ थी। मुझे लगता है कि मुझे इसे चिह्नित करने के लिए "/ s" का उपयोग करने की आवश्यकता है।
आर्टुरो टोरेस

@ ArturoTorresSánchez: यह एक प्रश्न और उत्तर साइट है; मैं उन सवालों पर विचार करता हूं जो ऐसे प्रश्न हैं जो उत्तर मांग रहे हैं ।
एरिक लिपर्ट

10

C # 7 में आप समान रूप से समान तरीके से प्राप्त करने के लिए पैटर्न मिलान का उपयोग कर सकते हैं:

if (myMessageQueue.TryDequeue() is Message dequeued) 
{
     MyMessagingClass.SendMessage(dequeued)
} 
else 
{
    Console.WriteLine("No messages!"); // do other stuff
}

हालांकि इस विशेष मामले में, मैं शायद बार-बार कतार में मतदान करने के बजाय घटनाओं का उपयोग करूंगा।


3
हालांकि ऐसा नहीं है कि कार्यान्वयन के TryDequeueसाथ कुछ मार्कर इंटरफ़ेस Messageऔर कुछ "कुछ भी नहीं" कार्यान्वयन को वापस करने की आवश्यकता है ? निश्चित रूप से, यह कॉल-साइट पर अधिक सुरुचिपूर्ण है, लेकिन आप वास्तविक कोड में 3 कार्यान्वयन लागू कर रहे हैं, जो Messageकि मौजूदा प्रकार का होने पर स्वयं असंभव हो सकता है।
तेलस्टिन

1
@Telastyn: यह भी काम करता है अगर यह सिर्फ शून्य देता है । आप एक विकल्प प्रकार का भी उपयोग कर सकते हैं।
जैक्सबी

@JacquesB: लेकिन क्या होगा यदि नल एक वैध योग्य वस्तु है?
जेबीएसनरो

5

एक कोशिश ... विधि (एक आउट पैरामीटर होने) के साथ कुछ भी गलत नहीं है एक परिदृश्य के लिए जिसमें विफलता (कोई मूल्य नहीं) बस सफलता के रूप में सामान्य है।

लेकिन, यदि आप चीजों को अलग तरीके से करने पर जोर देते हैं, तो आप एक खाली संदेश लौटाना चाह सकते हैं और या तो यह भेज सकते हैं (अब आपकी समस्या नहीं है) या यदि आप वास्तव में सामग्री के साथ एक संदेश है या नहीं, यह जानना चाहिए कि यदि आप वास्तव में जानना चाहते हैं तो बयान को स्थगित कर दें।

ध्यान दें कि किसी को किसी भी समय परीक्षण करना होगा। मैं तर्क दूंगा कि प्रश्न वर्तमान में कब और कहां होना चाहिए। यह छल के समय है।


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