क्या ये दोनों पंक्तियाँ एक जैसी हैं, '? …: 'बनाम ’??’?


80

क्या इन दोनों लाइनों में अंतर है?

MyName = (s.MyName == null) ? string.Empty : s.MyName

या

MyName = s.MyName ?? string.Empty

8
उनमें से IL की जाँच करें, इस तरह से आपके पास एक बेहतर विचार होगा यदि वे एक ही कोड का उत्पादन करेंगे या उन्हें अलग तरीके से संभाला जा रहा है
— manman

12
@manman यदि कोई उच्च स्तरीय कोड को नहीं समझता है तो आपको क्या आभास होता है कि IL कोड अधिक पठनीय होगा?
— 19

11
@ सर्वे जब कुछ अंतर जानने के लिए उत्सुक है और बाकी सभी लोग उच्च स्तरीय चर्चाओं को कवर कर रहे हैं, तो अंतर को समझने के अन्य तरीकों को इंगित करना एक अच्छा विचार है और यदि वह बहुत उत्सुक है, तो वह जा सकता है और परिणाम की तुलना कर सकता है, नहीं
— manman

6
फर्क सिर्फ इतना है कि आप s.MyNameएक या दो बार मूल्यांकन करते हैं ।
— टिम एस।

2
@ सरवाई क्योंकि आपको आईएल कोड को समझना नहीं है, आपको बस इसे करना diffहै
— wchargin

जवाबों:


166

अद्यतन: मैंने एक ब्लॉग पोस्ट लिखा है जो इस विषय पर अधिक गहराई से चर्चा करता है। http://www.codeducky.org/properties-fields-and-methods-oh-my/


आम तौर पर वे उसी परिणाम को वापस करेंगे। हालांकि, ऐसे कुछ मामले हैं जहां आप MyNameएक संपत्ति होने पर ध्यान देने योग्य मतभेदों का अनुभव करेंगे क्योंकि MyNameगेट्टर को पहले उदाहरण में दो बार निष्पादित किया जाएगा और केवल एक बार दूसरे उदाहरण में।

उदाहरण के लिए, आप MyNameदो बार निष्पादित करने से प्रदर्शन अंतर अनुभव कर सकते हैं :

string MyName
{
    get 
    {
        Thread.Sleep(10000);
        return "HELLO";
    }
}

या MyNameयदि MyNameआप स्टेटफुल हैं तो दो बार क्रियान्वयन से अलग परिणाम प्राप्त कर सकते हैं :

private bool _MyNameHasBeenRead = false;

string MyName
{
    get 
    {
        if(_MyNameHasBeenRead)
                throw new Exception("Can't read MyName twice");
        _MyNameHasBeenRead = true;
        Thread.Sleep(10000);
        return "HELLO";
    }
}

या MyNameयदि MyNameआप एक अलग धागे पर बदला जा सकता है तो दो बार निष्पादित करने से अलग परिणाम प्राप्त कर सकते हैं :

void ChangeMyNameAsync()
{
    //MyName set to null in another thread which makes it 
    //possible for the first example to return null
    Task.Run(() => this.MyName = null);
}

string MyName { get; set; }  

यहां बताया गया है कि वास्तविक कोड कैसे संकलित किया जाता है। पहले टर्नरी अभिव्यक्ति के साथ टुकड़ा:

IL_0007:  ldloc.0     // s
IL_0008:  callvirt    s.get_MyName       <-- first call
IL_000D:  brfalse.s   IL_0017
IL_000F:  ldloc.0     // s
IL_0010:  callvirt    s.get_MyName       <-- second call
IL_0015:  br.s        IL_001C
IL_0017:  ldsfld      System.String.Empty
IL_001C:  call        set_MyName

और यहाँ null-coalescing ऑपरेटर के साथ टुकड़ा है:

IL_0007:  ldloc.0     // s
IL_0008:  callvirt    s.get_MyName       <-- only call
IL_000D:  dup         
IL_000E:  brtrue.s    IL_0016
IL_0010:  pop         
IL_0011:  ldsfld      System.String.Empty
IL_0016:  call        s.set_MyName

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


3
MyName = s.MyName ?? string.EmptyMyNameप्रॉपर्टी होने पर दो बार गैटर को अंजाम नहीं देगा । इसलिए यदि आप दो बार गेट्टर को निष्पादित नहीं करना चाहते हैं, तो आपको दूसरी पंक्ति का उपयोग करना चाहिए।
— स्टीवन वेक्सलर

2
मैंने कोड के दो टुकड़ों के IL उदाहरणों को जोड़ने की स्वतंत्रता ली। एक पूर्ण LINQPad उदाहरण के लिए, dropbox.com/s/x6zqdsjlkosxchf/SO21052437.linq
— Lasse V. Karlsen

1
मुझे लगता है कि आप IL कोड के अंतिम भाग पर "s" से चूक गए हैं; वर्तमान में यह पढ़ता है et_MyName, जो होना चाहिए set_MyName।
— एजेन्संसफील्ड

2
इसके अलावा, उपरोक्त कारणों से ?:वास्तव में लंबे संस्करण का परिणाम हो सकता nullहै। यह अधिक सचित्र हो सकता है अगर "Value from other thread"ऊपर वास्तव में एक nullस्ट्रिंग था। फिर यह दिखाएगा कि परिणाम शून्य हो सकता है। यदि वस्तु getएग्रीकल्चर के पहले आह्वान पर एक स्ट्रिंग इंस्टेंस को वापस करने और केवल दूसरे इनवोकेशन पर नल को वापस करने का निर्णय लेती है, तो स्टेटफुल ऑब्जेक्ट के साथ भी ऐसा हो सकता है ।
— जेपी स्टिग नीलसन

2
यह भी ध्यान दें कि C # 4.0 भाषा चश्मा सुनिश्चित करता है (.17.14 में) कि MyValue वास्तव में दो बार मूल्यांकन करता है, इस प्रकार घबराहट को रोकने के लिए उस डबल कॉल को अनुकूलित करने के लिए (जैसा कि मैंने सोचा था कि यह पहली बार में होगा)
— ब्लैकबियर

26

यदि संपत्ति एक साधारण गेट्टर से अधिक है, तो आप पहले वाले के लिए गैर-शून्य मामले में दो बार एक फ़ंक्शन निष्पादित कर सकते हैं।

यदि संपत्ति एक राज्य वस्तु में है, तो संपत्ति के लिए दूसरा कॉल एक अलग परिणाम दे सकता है:

class MyClass
{
    private IEnumerator<string> _next = Next();

    public MyClass()
    {
        this._next.MoveNext();
    }

    public string MyName
    {
        get
        {
            var n = this._next.Current;
            this._next.MoveNext();
            return n;
        }
    }


    public static IEnumerator<string> Next()
    {
        yield return "foo";
        yield return "bar";
    }
}

इसके अलावा, गैर-स्ट्रिंग मामले में, वर्ग अधिभार == को टर्नरी ऑपरेटर की तुलना में कुछ अलग करने के लिए हो सकता है। मुझे विश्वास नहीं है कि टर्नरी ऑपरेटर को ओवरलोड किया जा सकता है।


टर्नरी ऑपरेटर निश्चित रूप से अतिभारित नहीं किया जा सकता है। यहां तक ​​कि C ++, जो आपको व्यावहारिक रूप से हर दूसरे ऑपरेटर को अधिभार देता है, ओवरलोडिंग का कोई तरीका नहीं है ?:। मैंने कोई भाषा नहीं देखी है जो करती है।
— डारेल हॉफमैन

@DarrelHoffman वहाँ हमेशा स्काला है, जहाँ आप अपना रोल कर सकते हैं;)
— jdphenix

9

फर्क सिर्फ इतना है कि आप s.MyNameदो बार या एक बार मूल्यांकन करते हैं । पहला ऐसा दो बार करेगा जो s.MyNameशून्य नहीं है, दूसरा केवल एक बार इसका मूल्यांकन करेगा।

ज्यादातर मामलों में, यह अंतर मायने नहीं रखता है, और मैं दूसरे के साथ जाऊंगा क्योंकि यह अधिक स्पष्ट और संक्षिप्त है।


5

हां, दोनों समान हैं, और यह अशक्त-संचालक है ।

यदि ऑपरेंड शून्य नहीं है, तो यह बाएं हाथ का ऑपरेंड देता है; अन्यथा यह दाहिने हाथ का ऑपरेंड लौटाता है।

अगर हम दक्षता की बात करें तो

string MyName = (s.MyName == null) ? string.Empty : s.MyName;
string MyName2 = s.MyName ?? string.Empty;

यदि मैं एक असेंबलर का उपयोग करता हूं तो मैं देख सकता हूं कि पहले बयान को संकलक द्वारा निष्पादित करने के लिए 19 बयानों की आवश्यकता है जबकि दूसरे कथन को निष्पादित करने के लिए केवल 12 बयानों की आवश्यकता है ।


नाम का उल्लेख करने के लिए धन्यवाद। मैं देखना चाहता था कि क्या जावा में भी यह है ?? ऑपरेटर। और यह नहीं है, इसलिए मैं दोनों के लिए सहायक ऑपरेटर के साथ रहूँगा।
— developerwjk


0

वे एक ही कार्य को पूरा करते हैं।

केवल अंतर पठनीयता के रूप में होगा कि क्या आपके सहकर्मी या जिसे पढ़ रहा है वह कोड को सिंटैक्स समझता है।

EDIT: इसके अतिरिक्त पहला विकल्प संपत्ति का MyNameदो बार मूल्यांकन कर सकता है ।


-1

नहीं। दोनों एक ही काम कर रहे हैं। दूसरा कुशल है। अगर यह शून्य नहीं है, तो वास्तविक मूल्य लौटाता है। दाहिने हाथ की ओर का मूल्य वापस किया जाएगा।

इस http://msdn.microsoft.com/en-us/library/ms173224.aspx को देखें

उम्मीद है की यह मदद करेगा।

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