2009-11-06 9 views
23

तो क्या मैं चिंतित हूं ?? ऑपरेटर, लेकिन अभी भी इसका उपयोग करने में असमर्थ रहा है। मैं आमतौर पर इसके बारे में सोचो, जब मैं की तरह कुछ कर रहा हूँ:सी # का कितना उपयोगी है ?? ऑपरेटर?

var x = (someObject as someType).someMember; 

तो someObject वैध है और someMember रिक्त है, मैं कर सकता

var x = (someObject as someType).someMember ?? defaultValue; 

लेकिन लगभग हमेशा मैं समस्याओं में मिलता है जब someObject रिक्त है, तथा ?? मुझे खुद को शून्य जांचने से कोई क्लीनर बनाने में मदद नहीं करता है।

क्या आप लोगों के लिए क्या उपयोग किया जाता है ?? व्यावहारिक स्थितियों में?

+9

FYI साथ इसे का उपयोग किया गया है: ?? नल कोलेसिंग ऑपरेटर कहा जाता है। –

+0

हां, बिल्कुल मैं क्या सोच रहा हूं। – Ruben

+0

मुझे लगता है कि यह एक "समुदाय विकी" होना चाहिए। –

उत्तर

26

मैं आपसे सहमत हूं कि ?? ऑपरेटर आमतौर पर सीमित उपयोग का होता है - अगर कुछ शून्य है तो फॉल-बैक वैल्यू प्रदान करना उपयोगी होता है, लेकिन जब आप संपत्तियों में ड्रिलिंग जारी रखना चाहते हैं या कभी-कभी तरीकों से नल संदर्भ अपवाद को रोकने के लिए उपयोगी नहीं है- शून्य संदर्भ।

IMHO, क्या अधिक से अधिक की आवश्यकता है ?? एक "शून्य-dereference" ऑपरेटर है जो आपको लंबी संपत्ति और/या विधि श्रृंखलाओं को एक साथ श्रृंखला की अनुमति देता है, उदा। a.b().c.d().e नल-नेस के लिए प्रत्येक मध्यवर्ती चरण का परीक्षण किए बिना। Groovy भाषा में Safe Navigation operator है और यह बहुत आसान है।

सौभाग्य से, ऐसा लगता है कि सी # टीम इस फीचर अंतर से अवगत है। C# टीम के लिए यह connect.microsoft.com suggestion देखें, सी # भाषा में एक नल-डीरेंसेंस ऑपरेटर जोड़ने के लिए।

हमें इस तरह के सुविधाओं के लिए बहुत से अनुरोध मिलते हैं। "?" समुदाय में उल्लिखित संस्करण चर्चा हमारे दिल के निकट है - यह आपको पर प्रत्येक "डॉट" पर शून्य के लिए परीक्षण करने की अनुमति देता है, और मौजूदा के साथ अच्छी तरह से लिखता है ?? ऑपरेटर:

एक? .b? .c ?? डी

मतलब अगर कोई, ए.बी. या ए.बी.टी. नल उपयोग डी है।

हम भविष्य में रिलीज के लिए इस पर विचार कर रहे हैं, लेकिन यह सी # 4.0 में नहीं होगा।

एक बार फिर धन्यवाद,

मैड्स Torgersen, सी # भाषा अपराह्न

आप भी सी # में इस सुविधा चाहते हैं, कनेक्ट साइट पर suggestion करने के लिए अपने वोट जोड़ने! :-)

एक वैकल्पिक हल मैं इस सुविधा की कमी से बचने के लिए का उपयोग क्या this blog post में वर्णित है की तरह एक विस्तार विधि, कोड इस तरह की अनुमति देने के लिए है:

string s = h.MetaData 
      .NullSafe(meta => meta.GetExtendedName()) 
      .NullSafe(s => s.Trim().ToLower()) 

इस कोड को या तो h.MetaData.GetExtendedName().Trim().ToLower() देता है या यह रिटर्न शून्य अगर एच, एच। मेटाडेटा, या एच। मेटाडेटा। GetExtendedName() शून्य है। मैंने इसे शून्य या खाली तारों, या शून्य या खाली संग्रहों की जांच करने के लिए भी बढ़ाया है। यहां दिए गए कोड का उपयोग मैं इन एक्सटेंशन विधियों को परिभाषित करने के लिए करता हूं:

public static class NullSafeExtensions 
{ 
    /// <summary> 
    /// Tests for null objects without re-computing values or assigning temporary variables. Similar to 
    /// Groovy's "safe-dereference" operator .? which returns null if the object is null, and de-references 
    /// if the object is not null. 
    /// </summary> 
    /// <typeparam name="TResult">resulting type of the expression</typeparam> 
    /// <typeparam name="TCheck">type of object to check for null</typeparam> 
    /// <param name="check">value to check for null</param> 
    /// <param name="valueIfNotNull">delegate to compute if check is not null</param> 
    /// <returns>null if check is null, the delegate's results otherwise</returns> 
    public static TResult NullSafe<TCheck, TResult>(this TCheck check, Func<TCheck, TResult> valueIfNotNull) 
     where TResult : class 
     where TCheck : class 
    { 
     return check == null ? null : valueIfNotNull(check); 
    } 

    /// <summary> 
    /// Tests for null/empty strings without re-computing values or assigning temporary variables 
    /// </summary> 
    /// <typeparam name="TResult">resulting type of the expression</typeparam> 
    /// <param name="check">value to check for null</param> 
    /// <param name="valueIfNotNullOrEmpty">delegate to compute non-null value</param> 
    /// <returns>null if check is null, the delegate's results otherwise</returns> 
    public static TResult CheckNullOrEmpty<TResult>(this string check, Func<string, TResult> valueIfNotNullOrEmpty) 
     where TResult : class 
    { 
     return string.IsNullOrEmpty(check) ? null : valueIfNotNullOrEmpty(check); 
    } 
    /// <summary> 
    /// Tests for null/empty collections without re-computing values or assigning temporary variables 
    /// </summary> 
    /// <typeparam name="TResult">resulting type of the expression</typeparam> 
    /// <typeparam name="TCheck">type of collection or array to check</typeparam> 
    /// <param name="check">value to check for null</param> 
    /// <param name="valueIfNotNullOrEmpty">delegate to compute non-null value</param> 
    /// <returns>null if check is null, the delegate's results otherwise</returns> 
    public static TResult CheckNullOrEmpty<TCheck, TResult>(this TCheck check, Func<TCheck, TResult> valueIfNotNullOrEmpty) 
     where TCheck : ICollection 
     where TResult : class 
    { 
     return (check == null || check.Count == 0) ? null : valueIfNotNullOrEmpty(check); 
    } 
} 
+0

मुझे सहायक विधि का विचार पसंद है, लेकिन यह दुखद है कि इसे ऐसा हैक होना है। – captncraig

+0

हाँ। यदि आप इसे सी # में प्राप्त करना चाहते हैं, तो प्रक्रिया को जल्दी से करने का एक आसान तरीका है: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=432830 पर सुझाव के लिए वोट दें! :-) –

+0

404 "सुरक्षित-शून्य-डीरफ़्रेंसिंग ऑपरेटर" लिंक पर। और माइक्रोसॉफ्ट कनेक्ट लिंक पर भी। –

7

?? असल में एक शून्य जांच ऑपरेटर है।

कारण अपने कोड मुसीबत में हो जाता है

है कि अगर "someObject रिक्त है, तो .someMember एक अशक्त वस्तु पर एक संपत्ति है आप पहली बार अशक्त के लिए someObject जाँच करना होगा

संपादित करें:।।

मुझे यह हां जोड़ना चाहिए, मुझे बहुत उपयोगी होना चाहिए, खासकर डेटाबेस इनपुट को संभालने में, विशेष रूप से LINQ से, लेकिन अन्य मामलों में भी। मैं इसे भारी उपयोग करता हूं।

22

मैं आमतौर पर तारों या नाखून के लिए इसका उपयोग करता हूं प्रकार

string s = someString ?? "Default message"; 

तुलना में आसान

string s; 
    if(someString == null) 
    s = "Default Message";   
    else 
    s = someString; 

या

है
string s = someString != null ? someString : "Default Message"; 
+2

बहुत सच है, लेकिन यह आपके मध्य कथन के बराबर नहीं है जैसे कि कुछ स्ट्रिंग == स्ट्रिंग। लक्षण, ?? ऑपरेटर आग नहीं लगेगा। –

+1

@ द लंग डक, आप सही हैं। एक खाली स्ट्रिंग एक नल स्ट्रिंग के समान नहीं है, यह सिर्फ एक उदाहरण था। वास्तव में मैं नल जांच के साथ स्ट्रिंग चेक को प्रतिस्थापित कर सकता था। जो मुझे करना चाहिए ... – Brandon

+1

स्ट्रिंग भी देखें। INNullOrEmpty (ओं)। – TrueWill

30

?? ऑपरेटर एसक्यूएल में coalesce विधि की तरह, यह आप पहली गैर शून्य मान हो जाता है।

var result = value1 ?? value2 ?? value3 ?? value4 ?? defaultValue; 
+1

अच्छा, इस तरह इसका उपयोग करने का कभी सोचा नहीं! – TheSean

+0

मैं एक परिस्थिति का उपयोग नहीं कर सकता ?? इस तरह से एक बेहतर डिजाइन खत्म नहीं होगा। एक अच्छा उपयोग मामला दिलचस्प होगा। – jphofmann

+2

@jphofmann: मेरे वर्तमान काम से एक अच्छा उपयोग मामला। मुझे फ़ंक्शन को कॉल करके जटिल व्यावसायिक ऑब्जेक्ट खोजना है। यदि खोज विफल रहता है तो खोज फ़ंक्शन द्वारा वापस किया जाता है। ऑब्जेक्ट मिलने तक मुझे बार-बार विभिन्न खोज पैरामीटर खोजना पड़ता है। खोज नियमों को कोड से बहुत आसानी से समझा जाता है: 'var result = Find (" ए ") ?? खोजें ("वाई") ?? ढूंढें ("क्यू"); ''?? का उपयोग करके आपका कोड अधिक कॉम्पैक्ट और पठनीय बना सकता है। –

1

आपके मामले में आप एक स्थिर संपत्ति के रूप में DefaultObject बना सकते हैं और नीचे की तरह उपयोग कर सकते हैं ...

var x = (someObject as someType ?? someType.DefaultObject).someMember; 

जहाँ आपके DefaultObject एक स्थिर, केवल पढ़ने के लिए वस्तु वापस आ जाएगी।

तरह EventArgs.Empty, String.Empty आदि ...

+0

यह मेरे लिए खतरनाक व्यवसाय की तरह लगता है। अगर मैं किसी ऑब्जेक्ट की संपत्ति चाहता हूं, जब तक यह शून्य न हो, तो इस कोड के परिणामस्वरूप ऐसी परिस्थितियां होंगी जहां मुझे यह भी पता नहीं है कि ऑब्जेक्ट मौजूद है या नहीं; हो सकता है कि यह किसी संपत्ति को 'डिफ़ॉल्ट ऑब्जेक्ट' के साथ साझा करने के लिए होता है, या हो सकता है कि यह शून्य हो। –

+0

@ डैन, यदि आप परवाह है कि ऑब्जेक्ट मौजूद है या नहीं, तो कुछ ऑब्जेक्ट == शून्य देखें। यदि आप बस उपयोगकर्ता को कुछ पठनीय प्रदर्शित करना चाहते हैं, तो SomeType.DefaultObject का उपयोग करें। एफवाईआई, इस रिफैक्टरिंग को नल ऑब्जेक्ट का परिचय कहा जाता है। –

0

मैं आप के रूप में ठीक उसी समस्या थी गया है, लेकिन LinqToXML एक टैग का उपयोग कर दस्तावेज़ में नहीं हो सकता है की अंतरिक्ष में इतना ?? प्रतिसाद नहीं का उपयोग कर उस टैग पर संपत्ति को एकत्रित करने के लिए व्यवहार्य नहीं है।

चूंकि सी # में वैश्विक चर के रूप में ऐसी कोई चीज नहीं है, सबकुछ कक्षा में है, इसलिए मुझे लगता है, जैसे ?? ज्यादातर बेकार है।

यहां तक ​​कि एक साधारण संपत्ति गेटर की तरह:

MyObject MyObj() { get { return _myObj ?? new MyObj(); } } 

शायद बेहतर एक प्रारंभकर्ता द्वारा कार्य किया है ...

मैं कल्पना है कि SQL में है जैसे कि यह LINQ क्वेरी में कुछ हद तक उपयोगी होगा, लेकिन मैं यह कर सकते हैं इस पल में वास्तव में एक प्राप्त नहीं है।

+0

डिफ़ॉल्ट (MyObj)? इसका क्या मतलब है? वैसे भी यह शून्य होगा? –

+0

हाहा, हाँ आप सही हैं ... – Pickle

2

सबसे उपयोगी है जब निरर्थक प्रकारों से निपटना है।

bool? whatabool; 
//... 
bool realBool = whatabool ?? false; 

बिना ?? आपको निम्नलिखित लिखना होगा, जो अधिक भ्रमित है।

bool realbool = false; 
if (whatabool.HasValue) 
    realbool = whatabool.Value; 

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

+0

बिना इसका प्रतिनिधित्व करने का एक कॉम्पैक्ट तरीका ?? है: बूल realBool = (whatabool == शून्य)? झूठा: व्हाटबूल; –

1

मैं इसे उन तरीकों से काम करने में उपयोग करता हूं जो सामान्य ऑपरेशन के तहत शून्य लौट सकते हैं।

उदाहरण के लिए, मान लें कि मेरे पास एक कंटेनर क्लास है जिसमें एक गेट विधि है जो कंटेनर में कोई कुंजी नहीं है (या शायद शून्य एक वैध संघ है)।

string GetStringRep(object key) { 
    object o = container.Get(key) ?? "null"; 
    return o.ToString(); 
} 

स्पष्ट रूप से, इन दो दृश्यों के बराबर हैं:

foo = bar != null ? bar : baz; 
foo = bar ?? baz; 

दूसरा केवल अधिक संक्षिप्त है तो मैं कुछ इस तरह कर सकते हैं।

+0

दरअसल, यह 100% सच नहीं है। टर्नरी ऑपरेटर नल कोलेसिंग ऑपरेटर से आईएल का एक अलग अनुक्रम उत्पन्न करता है। ldloc.0 brfalse.s isnull1 ldloc.0 isnull1 notnull1 br.s: ldstr "डिफ़ॉल्ट" notnull1: stloc.1 और इस तरह की तरह दिखता है उत्तरार्द्ध: इस तरह की पहली तरह दिखता है ldloc.0 notnull2 पॉप ldstr "डिफ़ॉल्ट" notnull2 dup brtrue.s: stloc.1 इस के आधार पर, मैं कहना चाहता हूँ अशक्त कोलेसिंग ऑपरेटर अपने उद्देश्य के लिए अनुकूलित और सिर्फ शुद्ध वाक्यात्मक चीनी नहीं है। –

+0

और मैं निश्चित रूप से स्वरूपण स्नफू के लिए क्षमा चाहता हूं। ओह। मैं इसे थोड़ा क्लीनर देखने के उत्तर के रूप में पोस्ट करूंगा। –

+0

जबकि आईएल अलग है, अर्थशास्त्र समकक्ष बना रहता है। – captncraig

1

यह अक्सर एक अधिक कॉम्पैक्ट रूप के साथ वाक्यविन्यास के वर्बोज़ बिट को प्रतिस्थापित करने का एक अच्छा विचार प्रतीत होता है। लेकिन आमतौर पर यह वास्तव में कुछ हासिल करने के बिना कोड को खराब कर देता है। आधुनिक मानकों को अधिक पठनीय & अधिक रखरखाव करने के लिए लंबे और अधिक वर्णनात्मक चर नामों और अधिक वर्बोज़ लेआउट शैलियों का उपयोग करने की सलाह दी जाती है।

यदि मैं अपने दिमाग को जल्दी से पार्स करने के लिए प्रशिक्षित करने जा रहा हूं ??, मुझे ऐसी स्थिति खोजने की ज़रूरत है जहां यह स्पष्ट लाभ दिखाए - कुछ ऐसा नहीं किया जा सकता है, या कहीं भी यह एक महत्वपूर्ण राशि बचाता है टाइपिंग का

और यह कहां है ?? मेरे लिए गिरता है। यह इतनी बार उपयोगी है और?: और यदि/अन्य ऐसे त्वरित और पठनीय विकल्प हैं जो वास्तव में एक अलग वाक्यविन्यास का उपयोग करने में थोड़ा सा बिंदु लगता है जो कुछ नया नहीं प्राप्त करता है।

ए = बी ?? सी ?? डी ?? ई; बहुत अच्छा लगता है। लेकिन मुझे ऐसा करने की ज़रूरत नहीं है!

मुझे जो परेशान लगता है वह है कि मैं उपयोग करना चाहता हूं ??, लेकिन हर बार मुझे लगता है कि "ओह, शायद मैं इसका उपयोग कर सकता हूं?", मुझे एहसास है कि मैं ऑब्जेक्ट का उपयोग नहीं करना चाहता, लेकिन इसका एक सदस्य

नाम = (उपयोगकर्ता == शून्य)? "डो": उपयोगकर्ता। नाम;

और दुर्भाग्य से ,?? यहाँ मदद नहीं करता है।

+0

पीएस मैं वेब पेज या LINQ डेटाबेस क्वेरीज विकसित नहीं करता, हालांकि, शायद हो सकता है ?? सिर्फ प्रोग्रामिंग की एक अलग शैली के उद्देश्य से है ... –

11

मैं अक्सर गुणों में आलसी तत्काल वस्तुओं के लिए इसका उपयोग करता हूं, उदा।

public MyObject MyProperty 
{ 
    get 
    { 
     return this.myField ?? (this.myField = new MyObject()); 
    } 
} 

इस तथ्य यह है कि सी # में एक काम एक अभिव्यक्ति है ताकि आप निर्दिष्ट करेंगे और अभिव्यक्ति (सौंपा मूल्य) सभी एक ही बयान में का परिणाम का उपयोग कर सकते का लाभ लेता है। मैं अभी भी इस कोड पैटर्न के बारे में थोड़ा गंदा महसूस करता हूं, लेकिन यह विकल्प (नीचे) से भी कम है, इसलिए यह जीत के बारे में है।

public MyObject MyProperty 
{ 
    get 
    { 
     if (this.myField == null) 
     { 
      this.myField = new MyObject(); 
     } 

     return this.myField; 
    } 
} 
+1

अच्छा। अतिरिक्त अंक यदि आप इसे थ्रेडसेफ भी बना सकते हैं, तब भी इसे एक पंक्ति पर रखते हुए :-) –

7
बस एक के रूप में

FYI करें, त्रिगुट ऑपरेटर अशक्त कोलेसिंग ऑपरेटर से आईएल का एक अलग अनुक्रम उत्पन्न करता है।

// string s = null; 
// string y = s != null ? s : "Default"; 
    ldloc.0 
    brtrue.s notnull1 
    ldstr "Default" 
    br.s isnull1 
    notnull1: ldloc.0 
    isnull1: stloc.1 

और इस तरह की तरह दिखता है उत्तरार्द्ध:

// y = s ?? "Default"; 
    ldloc.0 
    dup 
    brtrue.s notnull2 
    pop 
    ldstr "Default" 
    notnull2: stloc.1 

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

0

मैं अन्य डेटा प्रकारों में स्ट्रिंग को पार्स करते समय अक्सर नल-कोलेसिंग ऑपरेटर का उपयोग करता हूं। मेरे पास एक्सटेंशन विधियों का एक सेट है जो Int32.TryParse जैसी चीज़ों को लपेटता है और मेरे शेष कोड में आउटपुट पैरामीटर को उजागर करने के बजाए एक निरर्थक int वापस करता है। फिर मैं स्ट्रिंग को पार्स कर सकता हूं और कोड की एक पंक्ति में पार्स विफल होने पर डिफ़ॉल्ट मान प्रदान कर सकता हूं।

// ToNullableInt(), is an extension method on string that returns null 
// if the input is null and returns null if Int32.TryParse fails. 

int startPage = Request.QueryString["start"].ToNullableInt() ?? 0; 
3

मैं app.config सामान

string somethingsweet = ConfigurationManager.AppSettings["somesetting"] ?? "sugar"; 
संबंधित मुद्दे