C # में, जब आप किसी अशक्त वस्तु पर एक्सटेंशन विधि कहते हैं, तो क्या होता है?


328

क्या विधि को शून्य मान के साथ कहा जाता है या यह एक शून्य संदर्भ अपवाद देता है?

MyObject myObject = null;
myObject.MyExtensionMethod(); // <-- is this a null reference exception?

अगर यह मामला है तो मुझे अपने 'इस' पैरामीटर को अशक्त करने के लिए जाँच करने की आवश्यकता नहीं होगी?


बेशक, आप ASP.NET MVC के साथ काम कर रहे हैं जो इस त्रुटि को फेंक देगा Cannot perform runtime binding on a null reference
मृकफिन ५

जवाबों:


386

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

public static bool IsNullOrEmpty(this string value)
{
    return string.IsNullOrEmpty(value);
}
public static void ThrowIfNull<T>(this T obj, string parameterName)
        where T : class
{
    if(obj == null) throw new ArgumentNullException(parameterName);
}

आदि

मौलिक रूप से, स्टैटिक कॉल्स के लिए कॉल बहुत शाब्दिक हैं - यानी

string s = ...
if(s.IsNullOrEmpty()) {...}

हो जाता है:

string s = ...
if(YourExtensionClass.IsNullOrEmpty(s)) {...}

जहाँ जाहिर तौर पर कोई अशक्त जाँच नहीं है।


1
मार्क, आप "वर्चुअल" कॉल के बारे में बात कर रहे हैं - लेकिन उदाहरण के तरीकों पर गैर-आभासी कॉल के लिए भी यही सच है। मुझे लगता है कि यहाँ शब्द "आभासी" गलत है।
कोनराड रुडोल्फ

6
@ कोनराड: यह संदर्भ पर निर्भर करता है। C # संकलक आमतौर पर गैर-आभासी तरीकों के लिए भी कॉलविर्ट का उपयोग करता है, ठीक से एक अशक्त चेक प्राप्त करने के लिए।
जॉन स्कीट

मैं कॉल और कॉलविर्ट आईएल निर्देशों के बीच अंतर का उल्लेख कर रहा था। एक संपादन में मैं वास्तव में दो opcodes पृष्ठों href करने की कोशिश की, लेकिन संपादक लिंक पर barfed ...
मार्क Gravell

2
मैं नहीं देखता कि विस्तार के तरीकों का यह उपयोग वास्तव में कितना उपयोगी हो सकता है। सिर्फ इसलिए कि यह किया जा सकता है इसका मतलब यह नहीं है कि यह सही है, और जैसा कि नीचे वर्णित बाइनरी वॉरियर, यह मुझे कम से कम कहने के लिए एक विपथन की तरह लगता है।
जाल

3
@ ट्रैप: यदि आप कार्यात्मक शैली की प्रोग्रामिंग में हैं तो यह सुविधा बहुत अच्छी है।
राय टिंकर

50

मार्क ग्रेवेल से सही उत्तर के लिए जोड़।

आप संकलक से चेतावनी प्राप्त कर सकते हैं यदि यह स्पष्ट है कि यह तर्क शून्य है:

default(string).MyExtension();

रनटाइम में अच्छी तरह से काम करता है, लेकिन चेतावनी पैदा करता है "Expression will always cause a System.NullReferenceException, because the default value of string is null"


32
यह क्यों चेतावनी देगा "हमेशा एक System.NullReferenceException"। जब वास्तव में, यह कभी नहीं होगा?
शक्ति

46
सौभाग्य से, हम प्रोग्रामर केवल त्रुटियों की परवाह करते हैं, चेतावनियों की नहीं: पी
जूलियनआर

7
@ जूलियनआर: हां, कुछ करते हैं, कुछ नहीं। हमारे रिलीज़ बिल्ड कॉन्फ़िगरेशन में, हम चेतावनी को त्रुटियों के रूप में मानते हैं। तो यह सिर्फ काम नहीं करता है।
स्टीफन स्टाइनगर

8
नोट के लिए धन्यवाद; मुझे यह बग डेटाबेस में मिलेगा और हम देखेंगे कि क्या हम इसे C # 4.0 के लिए ठीक कर सकते हैं। (कोई वादा नहीं - चूंकि यह एक अवास्तविक कोने का मामला है और केवल एक चेतावनी है, हम इसे ठीक करने पर विचार कर सकते हैं।)
एरिक लिपर्ट

3
@Stefan: चूंकि यह बग है और "सही" चेतावनी नहीं है, आप कोड जारी करने के लिए चेतावनी जारी करने के लिए एक #pragma स्टेटमेंट का उपयोग कर सकते हैं।
मार्टिन आरएल

24

जैसा कि आप पहले ही खोज चुके हैं, चूंकि विस्तार विधियां केवल स्थैतिक तरीकों का महिमामंडन करती हैं, उन्हें nullबिना NullReferenceExceptionफेंके जाने वाले संदर्भों के साथ कहा जाएगा । लेकिन, चूंकि वे कॉल करने वाले के लिए उदाहरण के तरीकों की तरह दिखते हैं, इसलिए उन्हें भी इस तरह का व्यवहार करना चाहिए । आपको चाहिए कि, अधिकांश समय, thisपैरामीटर की जाँच करें और यदि अपवाद है तो उसे फेंक दें null। यह ठीक नहीं है यदि विधि स्पष्ट रूप से nullमूल्यों का ध्यान रखती है और इसका नाम विधिवत इंगित करता है, जैसे नीचे दिए गए उदाहरणों में:

public static class StringNullExtensions { 
  public static bool IsNullOrEmpty(this string s) { 
    return string.IsNullOrEmpty(s); 
  } 
  public static bool IsNullOrBlank(this string s) { 
    return s == null || s.Trim().Length == 0; 
  } 
}

मैंने कुछ समय पहले इस बारे में एक ब्लॉग पोस्ट भी लिखा है


3
इसे वोट किया क्योंकि यह सही है और मुझे (और अच्छी तरह से लिखा) समझ में आता है, जबकि मैं @Marc Gravell द्वारा उत्तर में वर्णित उपयोग को भी पसंद करता हूं।
21

17

एक नल विस्तार विधि से पारित किया जाएगा।

यदि विधि बिना जांच के वस्तु तक पहुंचने की कोशिश करती है, तो यह अशक्त है, हां, यह एक अपवाद फेंक देगा।

यहाँ एक व्यक्ति ने लिखा है "इसनॉल" और "इसनोटनॉल" विस्तार विधियाँ जो यह जाँचती हैं कि संदर्भ निल है या नहीं। व्यक्तिगत रूप से मुझे लगता है कि यह एक विपथन है और इसे दिन का प्रकाश नहीं देखा जाना चाहिए, लेकिन यह पूरी तरह से मान्य है #।


18
दरअसल, मेरे लिए यह एक लाश की तरह है "क्या आप जीवित हैं" और "नहीं" का जवाब पाने के लिए। एक लाश किसी भी सवाल का जवाब नहीं दे सकती है, न ही आपको एक अशक्त वस्तु पर एक विधि "कॉल" करने में सक्षम होना चाहिए।
बाइनरी वॉरियर

14
मैं बाइनरी वॉरियर के तर्क से असहमत हूं, क्योंकि यह नल रिफल्स के बारे में चिंता किए बिना एक्सटेंशन कॉल करने में सक्षम है, लेकिन एनालॉग कॉमेडी वैल्यू के लिए +1 :-)
टिम एबेल

10
वास्तव में, कभी-कभी आपको नहीं पता होता है कि कोई मर गया है, इसलिए आप अभी भी पूछते हैं, और वह व्यक्ति उत्तर दे सकता है, "नहीं, बस मेरी आँखें बंद हो गई हैं"
नुरची

7
जब आपको कई ऑपरेशनों की श्रृंखला की आवश्यकता होती है (3+ कहते हैं), तो आप बोरिंग बॉयलरप्लेट नल-चेकिंग कोड की कई पंक्तियों को "शून्य-सुरक्षित" एक्सटेंशन विधियों के साथ सुरुचिपूर्ण ढंग से जंजीर वाले वन-लाइनर में बदल सकते हैं। (सुझाए गए "" के समान है? "- ऑपरेटर, लेकिन स्पष्ट रूप से उतना सुरुचिपूर्ण नहीं है।) यदि यह स्पष्ट नहीं है कि एक विस्तार" अशक्त "है, तो मैं आमतौर पर" सुरक्षित "विधि के साथ उपसर्ग करता हूं, इसलिए यदि उदाहरण के लिए यह एक प्रति है- विधि, इसका नाम "SafeCopy" हो सकता है, और यदि तर्क शून्य था, तो यह अशक्त हो जाएगा।
anorZaken

3
मैं हंसी के साथ इतनी मेहनत कर रहा था @BinaryWorrier जवाब hahahaha मैंने खुद को जांचने के लिए एक शरीर को लात मारते हुए देखा कि क्या यह मृत था या नहीं हाहा तो मेरी कल्पना में, जिसने यह जांच की कि शरीर मृत था या नहीं और मैं खुद शरीर नहीं था, कार्यान्वयन जाँच मुझ में थी, सक्रियता से यह देखने के लिए कि क्या वह चलती है। तो एक शरीर को पता नहीं है कि यह मृत है या नहीं, डब्ल्यूएचओ जाँच करता है, जानता है, अब आप तर्क दे सकते हैं कि आप शरीर को "प्लगइन" कर सकते हैं इसके लिए आपको यह बताने का तरीका है कि क्या यह मृत है या नहीं और मेरी राय में यह क्या है एक एक्सटेंशन के लिए है
जोर्किंड

7

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

आप इस लेख को उदाहरणों के लिए पढ़ सकते हैं: साइक्लोमैटिक जटिलता को कैसे कम करें: गार्ड क्लॉज लघु संस्करण यह है:

public static class StringExtensions
{
    public static void AssertNonEmpty(this string value, string paramName)
    {
        if (string.IsNullOrEmpty(value))
            throw new ArgumentException("Value must be a non-empty string.", paramName);
    }
}

यह स्ट्रिंग क्लास एक्सटेंशन विधि है जिसे अशक्त संदर्भ पर कहा जा सकता है:

((string)null).AssertNonEmpty("null");

कॉल केवल ठीक काम करता है क्योंकि रनटाइम सफलतापूर्वक विस्तार विधि को शून्य संदर्भ पर कॉल करेगा। फिर आप इस एक्सटेंशन मेथड का इस्तेमाल गंदी सिंटैक्स के बिना गार्ड क्लॉज लागू करने के लिए कर सकते हैं:

    public IRegisteredUser RegisterUser(string userName, string referrerName)
    {

        userName.AssertNonEmpty("userName");
        referrerName.AssertNonEmpty("referrerName");

        ...

    }

3

एक्सटेंशनमेथोड स्थिर है, इसलिए यदि आप इस MyObject को कुछ भी नहीं देते हैं तो यह समस्या नहीं होनी चाहिए, एक त्वरित परीक्षण इसे सत्यापित कर सकता है :)


-1

जब आप अपने पढ़ने योग्य और लंबवत होना चाहते हैं तो कुछ सुनहरे नियम होते हैं।

  • एफिल से एक कहने लायक बात यह है कि एक विधि में कूटबद्ध विशिष्ट कोड को कुछ इनपुट के खिलाफ काम करना चाहिए, यह कोड काम करने योग्य है अगर कुछ पूर्व शर्त से मिले हैं और अपेक्षित आउटपुट का आश्वासन देते हैं

आपके मामले में - DesignByContract टूट गया है ... आप अशक्त उदाहरण पर कुछ तर्क करने जा रहे हैं।

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