C # के लिए प्रॉपर्टी-कोलेसिंग ऑपरेटर


9

N # में अशक्त-सहवर्ती ऑपरेटर आपको कोड को छोटा करने की अनुमति देता है

  if (_mywidget == null)
     return new Widget();
  else
     return _mywidget;

नीचे करने के लिए:

  return _mywidget ?? new Widget();

मुझे पता चलता है कि एक उपयोगी ऑपरेटर जिसे मैं सी # में रखना चाहता हूं वह वह होगा जो आपको किसी वस्तु की संपत्ति वापस करने की अनुमति देता है, या यदि वस्तु शून्य है तो कुछ अन्य मूल्य। इसलिए मैं बदलना चाहूंगा

  if (_mywidget == null)
     return 5;
  else
     return _mywidget.Length;

साथ में:

  return _mywidget.Length ??! 5;

मैं यह सोचने में मदद नहीं कर सकता कि इस ऑपरेटर के मौजूद न होने का कोई कारण होना चाहिए। क्या यह एक कोड गंध है? क्या इसे लिखने का कोई बेहतर तरीका है? (मैं अशक्त वस्तु पैटर्न से अवगत हूं, लेकिन कोड की इन चार पंक्तियों को बदलने के लिए इसका उपयोग करना अधिक कठिन लगता है।)


1
क्या सशर्त ऑपरेटर यहां पर्याप्त होगा?
आनन।

1
किसी ने कुछ लिखा है जो आपको इस तरह से कुछ करने में सक्षम बनाता है: स्ट्रिंग स्थान = कर्मचारी ।office.address.location ?? "अनजान"; । इस Wil सेट स्थान के लिए "अज्ञात" जब वस्तु (या तो में से एक कर्मचारी , कार्यालय , पता या स्थान ) रिक्त है। दुर्भाग्य से, मुझे याद नहीं है कि यह किसने लिखा है या उसने इसे कहाँ पोस्ट किया है। अगर मुझे यह फिर से मिल जाए, तो मैं इसे यहाँ पोस्ट करूँगा!
क्रिस्टोफ क्ले

1
इस सवाल को StackOverflow पर बहुत अधिक कर्षण मिलेगा।
जॉब

2
??!C ++ में एक ऑपरेटर है। :-)
जेम्स मैकनेलिस

3
हैलो 2011, बस यह कहने के लिए कि c # को एक सुरक्षित नेविगेशन ऑपरेटर
नाथन कूपर

जवाबों:


5

मैं बहुत सी एक सी # भाषा सुविधा चाहता हूं जो मुझे सुरक्षित रूप से x.Prop.SomeOtherProp.ThirdProp करने देता है, ताकि उनमें से प्रत्येक के लिए शून्य की जांच किए बिना। एक कोडबेस में, जहां मुझे "डीप प्रॉपर्टी ट्रैवर्सल्स" के उन प्रकारों को बहुत कुछ करना था, मैंने एक एक्सटेंशन विधि लिखी जिसे नेविगेट करना था जो NullReferenceException को निगल गया और इसके बजाय एक डिफ़ॉल्ट मान लौटाया। इसलिए मैं ऐसा कुछ कर सकता था:

var propVal = myThing.Navigate(x => x.PropOne.PropTwo.PropThree.PropFour, defaultValue);

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

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


1
वास्तव में मैंने क्या सोचा था, लेकिन सुरक्षित तरीके से प्रदर्शन काफी खराब होगा, मुझे लगता है कि (कई अभिव्यक्ति के कारण ।Compile ()) ... बहुत बुरा यह C # में लागू नहीं है (Obj.PPropA.PPP1 की तरह)
गुइलुइमोरी86

x.PropOne.PropTwo.PropThree.PropFour एक खराब डिजाइन विकल्प है क्योंकि यह कानून के कानून का उल्लंघन करता है। अपने तरीकों / कक्षाओं को फिर से डिज़ाइन करें ताकि आपको इसका उपयोग करने की आवश्यकता न हो।
जस्टिन शील्ड

कानूनविदों के प्रकाश में गहरी संपत्ति तक पहुंच को ध्यान में रखते हुए डेटाबेस को सामान्य रूप से खतरनाक बनाना उतना ही खतरनाक है। आप बहुत दूर जा सकते हैं।
मीर

3
C # 6.0 में यह Null-Conditional Operator (उर्फ द एल्विस ऑपरेटर) msdn.microsoft.com/en-us/magazine/dn802602.aspx
winorvartan

15

मेरा मानना ​​है कि आप सी # 6 के साथ ऐसा करने में सक्षम होंगे:

return _mywidget?.Length ?? 5;

?.बाईं ओर के नल-संचालक ऑपरेटर पर ध्यान दें । _mywidget?.Lengthयदि अशक्त है तो अशक्त देता _mywidgetहै।

एक साधारण टर्नरी ऑपरेटर को पढ़ना आसान हो सकता है, हालांकि, जैसा कि दूसरों ने सुझाव दिया है।


9

यह वास्तव में केवल अटकलें हैं कि उन्होंने ऐसा क्यों नहीं किया। आखिरकार, मुझे विश्वास नहीं हो रहा है ?? पहले C # संस्करण में था।

वैसे भी, मैं बस सशर्त ऑपरेटर का उपयोग करूंगा और इसे एक दिन कहूंगा:

return (_mywidget != null) ? _mywidget.Length : 5;

?? सशर्त ऑपरेटर का सिर्फ एक शॉर्टकट है।


5
व्यक्तिगत रूप से, यह पहले स्थान पर ऐसा करने के लिए एक ऑपरेटर होने के रूप में बुरा (imho) है। आप किसी वस्तु से कुछ चाहते हैं ... वह वस्तु वहां नहीं हो सकती ... तो आइए 5उस स्थिति में उत्तर के रूप में प्रदान करें जो वह नहीं है। विशेष ऑपरेटरों के लिए पूछना शुरू करने से पहले आपको अपने डिज़ाइन को देखना होगा।
मू-जूस

1
@ मू-रस मैं सिर्फ इस कोड को बनाए रखने वाले व्यक्ति की कल्पना कर रहा हूं, 'यह मुझे 5 क्यों दे रहा है? Hrmmm। क्या?!'
msarchet


3

व्यक्तिगत रूप से, मुझे लगता है कि यह पठनीयता के लिए नीचे है। पहले उदाहरण में, ??अनुवाद काफी अच्छी तरह से "क्या आप वहाँ हैं? नहीं, चलो यह करते हैं"।

दूसरे उदाहरण में, ??!स्पष्ट रूप से डब्ल्यूटीएफ और प्रोग्रामर के लिए कुछ भी नहीं है .... वस्तु मौजूद नहीं है, इसलिए मुझे संपत्ति नहीं मिल सकती है इसलिए मैं वापस लौटूंगा। 5. इसका क्या मतलब है? 5 क्या है? हम इस निष्कर्ष पर कैसे पहुंचे कि 5 एक अच्छा मूल्य है?

संक्षेप में, पहला उदाहरण समझ में आता है ... वहाँ नहीं, नया । दूसरे में, यह बहस के लिए खुला है।


2
खैर, आपको इस तथ्य को अनदेखा करना होगा कि ??! मौजूद नहीं है। सोचिए अगर ?? आम था, और अगर इसका उपयोग किया गया था, तो उसी के आधार पर निर्णय लें।
whatsisname

3
यही कारण है कि मुझे तथाकथित "WTF ऑपरेटर" C ++ की याद दिलाता है (यह वास्तव में काम करता है: (foo() != ERROR)??!??! cerr << "Error occurred" << endl;।)
तमस Szelei

@whatsisname, यह इस तथ्य पर अधिक प्रतिबिंब था कि यह निर्णय के लिए उपयुक्त था। ऑब्जेक्ट बनाने के लिए क्योंकि यह वहां नहीं था। एक मध्यस्थता मूल्य निर्धारित करने के लिए जिसका अर्थ है कि पाठक को कुछ भी नहीं है क्योंकि आप किसी चीज़ की संपत्ति पर प्राप्त नहीं कर सकते हैं , वास्तव में एक डब्ल्यूटीएफ परिदृश्य है।
मू-जूस

मुझे लगता है कि आप मेरे उदाहरण में फंस गए हैं। हो सकता है कि 0 0 से बेहतर हो। हो सकता है कि संपत्ति एक वस्तु है इसलिए यदि _mywidget शून्य है, तो आप एक नया भोजन () वापस करना चाहते हैं। मैं पूरी तरह से असहमत हूँ कि ?? से अधिक पठनीय है ?? हालाँकि :)
बेन फुल्टन

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

2

मुझे लगता है कि लोग "5" में भी फंस गए हैं कि आप वापस लौट रहे हैं ... शायद 0 बेहतर होगा :)

वैसे भी, मुझे लगता है कि समस्या यह है कि ??!वास्तव में एक स्टैंडअलोन ऑपरेटर नहीं है। विचार करें कि इसका क्या अर्थ होगा:

var s = myString ??! "";

उस मामले में, इसका कोई मतलब नहीं है: यह केवल तभी समझ में आता है जब बाएं हाथ का ऑपरेंड एक संपत्ति एक्सेसर है। या इसके बारे में क्या:

var s = Foo(myWidget.Length) ??! 0;

वहाँ एक संपत्ति गौण है, लेकिन मुझे अभी भी नहीं लगता कि यह समझ में आता है (यदि myWidgetहै null, तो क्या इसका मतलब है कि हम बिल्कुल भी कॉल नहीं करते हैं Foo()?), या यह सिर्फ एक त्रुटि है?

मुझे लगता है कि समस्या यह है कि यह भाषा में स्वाभाविक रूप से फिट नहीं है जैसा कि ??करता है।


1

किसी ने एक उपयोगिता वर्ग बनाया था जो आपके लिए ऐसा करेगा। लेकिन मुझे यह नहीं मिल रहा है। मैंने जो पाया वह MSDN फ़ोरम पर कुछ समान था (दूसरे उत्तर को देखें)।

थोड़े काम के साथ, आप इसे विधि कॉल और अन्य अभिव्यक्तियों का मूल्यांकन करने के लिए बढ़ा सकते हैं जो नमूना समर्थन नहीं करता है। आप डिफ़ॉल्ट मान को स्वीकार करने के लिए इसे बढ़ा भी सकते हैं।


1

मुझे पता है कि आपका आगमन कहां से हो रहा है। ऐसा लगता है जैसे हर कोई आपके द्वारा दिए गए उदाहरण के साथ एक्सल के चारों ओर लपेट रहा है। जबकि मैं मानता हूं कि जादू की संख्या एक बुरा विचार है, कुछ गुणों के लिए एक अशक्त coallescing ऑपरेटर के बराबर का उपयोग होगा।

उदाहरण के लिए, आपके पास एक नक्शे से जुड़ी हुई वस्तुएं हैं, और आप उन्हें उचित ऊंचाई पर रखना चाहते हैं। DTED मैप्स में उनके डेटा में छेद हो सकते हैं, इसलिए अशक्त मान होना संभव है, साथ ही -100 से ~ 8900 मीटर तक कुछ की रेंज में मान। आप की तर्ज पर कुछ चाह सकते हैं:

mapObject.Altitude = mapObject.Coordinates.DtedAltitude ?? DEFAULT_ALTITUDE;

इस मामले में अशक्त coallescing ऑपरेटर डिफ़ॉल्ट ऊंचाई को पॉप्युलेट करेगा यदि Coordinates अभी तक सेट नहीं किए गए थे, या निर्देशांक ऑब्जेक्ट उस स्थान के लिए DTED डेटा लोड नहीं कर सका।

मैं इसे बहुत मूल्यवान के रूप में देखता हूं, लेकिन ऐसा करने के लिए मेरी अटकलें संकलक जटिलता तक सीमित नहीं हैं। ऐसे कुछ मामले हो सकते हैं जहां व्यवहार उतना अनुमान के मुताबिक नहीं होगा।


1

जब गहराई से नेस्टेड के साथ काम नहीं कर रहा हूं, तो मैंने इसका इस्तेमाल किया है (सी # 6 में पेश किए गए अशक्त coalescing ऑपरेटर से पहले)। मेरे लिए यह बहुत स्पष्ट है, लेकिन शायद इसलिए कि मैं इसका उपयोग कर रहा हूं, अन्य लोगों को यह भ्रामक लग सकता है।

return ( _mywidget ?? new MyWidget() {length = defaultLength}).Length;

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

एक अन्य विकल्प NullObject पैटर्न का उपयोग करना है । आप समझदार डिफ़ॉल्ट मानों के साथ वर्ग के एक एकल स्थिर उदाहरण को परिभाषित करते हैं, और इसके बजाय इसका उपयोग करते हैं।

return ( _mywidget ?? myWidget.NullInstance).Length;

0

मैजिक नंबर आमतौर पर एक बुरी गंध है। यदि 5 एक मनमाना संख्या है, तो इसे बाहर वर्तनी के लिए बेहतर है ताकि यह अधिक स्पष्ट रूप से प्रलेखित हो। मेरी राय में एक अपवाद यह होगा कि क्या आपके पास ऐसे मूल्यों का संग्रह है जो किसी विशेष संदर्भ में डिफ़ॉल्ट मानों के रूप में कार्य कर रहे हैं।

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

कुछ इस तरह: वापसी (myobj ?? default_obj)। गति


0

लंबाई संपत्ति आमतौर पर एक मूल्य प्रकार है इसलिए यह अशक्त नहीं हो सकती है, इसलिए अशक्त-सहवर्ती ऑपरेटर को यहां कोई मतलब नहीं है।

लेकिन आप उदाहरण के लिए, एक संपत्ति के साथ ऐसा कर सकते हैं: var window = App.Current.MainWindow ?? new Window();


उदाहरण पर विचार करने की कोशिश कर रहा है कि यदि आपकी स्थिति वर्तमान में शून्य थी तो क्या होगा। आपका उदाहरण बस दुर्घटनाग्रस्त हो जाएगा ... लेकिन एक ऑपरेटर के पास जो गलत सीमा श्रृंखला में कहीं भी मोटे तौर पर अशक्त कर सकता है।
मीर

-1

मैंने पहले भी किसी को इसी तरह के विचार के साथ देखा है, लेकिन अधिकांश समय आप नए मूल्य को शून्य क्षेत्र में असाइन करना चाहते हैं, जैसे कुछ:

return _obj ?? (_obj = new Class());

इसलिए विचार को असाइनमेंट ??और =असाइनमेंट में शामिल करना था:

return _obj ??= new Class();

मुझे लगता है कि विस्मयादिबोधक चिह्न का उपयोग करने से यह अधिक समझ में आता है।

यह विचार मेरा नहीं है, लेकिन मुझे वास्तव में पसंद है :)


1
क्या आप घटिया उदाहरण के शिकार हैं? आपके उदाहरण को छोटा किया जा सकता return _obj ?? new Class();है, ??=यहाँ की कोई आवश्यकता नहीं है।
मैट एलेन

@ मट्ट एलेन आपको यह गलत लगा। असाइनमेंट का इरादा है । मैं एक अलग विकल्प सुझा रहा हूं। यह बिल्कुल वैसा नहीं है जैसा ओपी ने पूछा था, लेकिन मेरा मानना ​​है कि यह उतना ही उपयोगी होगा।
चक्रित

2
यदि आप मान वापस करने जा रहे हैं तो आप असाइनमेंट क्यों चाहते हैं?
मैट एलेन

आलसी-आरंभीकरण?
chakrit
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.