एक ArgumentNullException को कैसे फेंकना मदद करता है?


27

मान लीजिए कि मेरे पास एक विधि है:

public void DoSomething(ISomeInterface someObject)
{
    if(someObject == null) throw new ArgumentNullException("someObject");
    someObject.DoThisOrThat();
}

मुझे यह विश्वास करने के लिए प्रशिक्षित किया गया है कि फेंकना ArgumentNullException"सही" है, लेकिन एक "ऑब्जेक्ट संदर्भ एक वस्तु के उदाहरण के लिए सेट नहीं है" त्रुटि का मतलब है कि मेरे पास एक बग है।

क्यूं कर?

मुझे पता है कि अगर मैं someObjectबाद में इसके संदर्भ का उपयोग कर रहा था और इसका उपयोग कर रहा था , तो यह बेहतर है कि जब यह पास हो जाए, तो अशक्तता की जांच करें और जल्दी विफल हो जाएं। हालाँकि, अगर मैं इसे अगली पंक्ति में डाल रहा हूँ, तो हमें चेक क्यों करना चाहिए? यह एक अपवाद को एक तरह से या दूसरे को फेंकने वाला है।

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

यह सिर्फ मेरे लिए हुआ ... क्या सी + + जैसी भाषा से डीरेल्ड नल का डर है जो आपके लिए जांच नहीं करता है (यानी यह सिर्फ स्मृति स्थान शून्य + विधि ऑफसेट पर कुछ विधि निष्पादित करने की कोशिश करता है)?


अपवाद को स्पष्ट करने से यह पुष्टि करने में मदद मिलती है कि त्रुटि की संभावना है, जिसे सीधे प्रलेखन में नोट किया जा सकता है।
zzzzBov

जवाबों:


34

मुझे लगता है कि अगर आप तुरंत चर को निष्क्रिय कर रहे हैं, तो आप किसी भी तरह से बहस कर सकते हैं, लेकिन मैं फिर भी तर्क को पसंद करूंगा।
यह बहुत स्पष्ट है कि क्या हो रहा है। अपवाद में वैरिएबल का नाम है जो अशक्त था, जबकि NullReferenceException नहीं है। विशेष रूप से एपीआई स्तर पर, एक ArgumentNullException यह स्पष्ट करता है कि कुछ कॉलर ने किसी विधि के अनुबंध का सम्मान नहीं किया था, और विफलता जरूरी नहीं कि एक यादृच्छिक त्रुटि या कुछ गहरा मुद्दा था (हालांकि यह अभी भी हो सकता है)। आपको जल्दी असफल होना चाहिए।

इसके अलावा, बाद में अनुरक्षकों को क्या करने की अधिक संभावना है? ArgumentNullException को जोड़ें, यदि वे पहली डीरेल से पहले कोड जोड़ते हैं, या केवल कोड जोड़ते हैं और बाद में NullReferenceException को फेंकने की अनुमति देते हैं?


विस्तार से, यदि यह एक गैर-सार्वजनिक विधि, या एक गैर-सार्वजनिक वर्ग पर एक सार्वजनिक विधि थी, तो आपको नहीं लगता कि अशक्त जांच का एक अच्छा कारण है?
स्कॉट व्हाइटलॉक

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

54

मुझे यह विश्वास करने के लिए प्रशिक्षित किया गया है कि ArgumentNullException को फेंकना "सही" है, लेकिन "ऑब्जेक्ट का संदर्भ ऑब्जेक्ट के इंस्टेंस पर सेट नहीं है" त्रुटि का अर्थ है कि मेरे पास बग है। क्यूं कर?

मान लीजिए कि मैंने M(x)आपके द्वारा लिखी गई विधि को कॉल किया । मैं अशक्त हो जाता हूं। मुझे "x" नाम के साथ एक ArgumentNullException मिलती है। यह अपवाद स्पष्ट रूप से इसका मतलब है कि मेरे पास एक बग है; मुझे x के लिए अशक्त नहीं होना चाहिए।

मान लीजिए कि मैंने एक विधि M को लिखा है जिसे आपने लिखा था। मैं अशक्त हो जाता हूं। मुझे एक अशक्त अपवाद मिलता है। मुझे यह कैसे पता होना चाहिए कि मेरे पास बग है या आपके पास बग या कोई थर्ड पार्टी लाइब्रेरी है जिसे आपने मेरी ओर से बुलाया था ? मुझे इस बारे में कुछ नहीं पता कि मुझे अपना कोड ठीक करने की जरूरत है या आपको ठीक करने के लिए आपको फोन करने की जरूरत है।

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


मुझे यकीन नहीं है कि मुझे समझ में आया "neither should ever be thrown in production code"है कि वे किस प्रकार के कोड / स्थितियों का उपयोग करेंगे? क्या उन्हें जैसे संकलित किया जाना चाहिए Debug.Assert? या आप इसका मतलब यह है कि उन्हें एक एपीआई से बाहर नहीं फेंक दिया?
स्टुपरयूजर

6
@ स्टॉपरयूज़र: मुझे लगता है कि आप गलत समझ रहे थे कि मेरा क्या मतलब है, क्योंकि मैंने इसे भ्रामक तरीके से लिखा था। आप चाहिए है throw new ArgumentNullExceptionअपने उत्पादन कोड में, और यह एक टेस्ट केस के बाहर कभी नहीं चलाना चाहिए । अपवाद को वास्तव में कभी नहीं फेंकना चाहिए क्योंकि कॉलर को कभी भी बग नहीं होना चाहिए।
एरिक लिपर्ट

1
न केवल यह बताता है कि बग किसके पास है, यह बताता है कि बग कहां है। यहां तक ​​कि अगर दोनों क्षेत्र मेरे हैं, तो यह समझना बिल्कुल आसान नहीं है कि चर क्या था।
ओहद श्नाइडर

5

मुद्दा यह है, आपके कोड को कुछ सार्थक करना चाहिए।

NullReferenceExceptionविशेष रूप से सार्थक नहीं है, क्योंकि यह सब कुछ के बारे में मतलब हो सकता है। यह देखे बिना कि अपवाद कहाँ फेंका गया था (और कोड मेरे लिए उपलब्ध नहीं हो सकता है) मैं यह पता नहीं लगा सकता कि क्या गलत हुआ।

एक ArgumentNullExceptionसार्थक है, क्योंकि यह मुझे बताता है: ऑपरेशन विफल हो गया क्योंकि तर्क someObjectथा null। मुझे यह पता लगाने के लिए आपके कोड को देखने की आवश्यकता नहीं है।

इस अपवाद को बढ़ाने का अर्थ है, कि आप स्पष्ट रूप से संभालते हैं null, भले ही आपका एकमात्र तरीका यह कहना है, कि आप इसे संभाल नहीं सकते हैं, जबकि कोड को क्रैश करने का अर्थ संभवतः यह हो सकता है कि, आप वास्तव में अशक्त को संभालने में सक्षम हो सकते हैं। , लेकिन मामले को लागू करने के लिए भूल गया।

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


2

मेरा मानना ​​है कि यह केवल फायदा है कि आप अपवाद में बेहतर निदान प्रदान कर सकते हैं। क्या आप जानते हैं, कि फ़ंक्शन का कॉलर शून्य से गुजर रहा है, जबकि यदि आप डीरेफेरेंस को फेंकने देते हैं, तो आपको यकीन नहीं होगा कि कॉलर गलत डेटा पास करता है या फ़ंक्शन में ही कोई बग है।

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


1

मुझे यह विश्वास करने के लिए प्रशिक्षित किया गया है कि ArgumentNullException को फेंकना "सही" है, लेकिन "ऑब्जेक्ट का संदर्भ ऑब्जेक्ट के इंस्टेंस पर सेट नहीं है" त्रुटि का अर्थ है कि मेरे पास बग है।

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

समान कारणों से जो ApplicationExceptionआपके एप्लिकेशन बनाम सामान्य Exceptionसे संबंधित है जो ऑपरेटिंग सिस्टम से संबंधित है। अपवाद के प्रकार को इंगित किया जाता है जहां अपवाद उत्पन्न होता है।

यदि आपने शून्य के लिए जिम्मेदार है, तो बेहतर है कि आप इसे एक विशिष्ट अपवाद को फेंककर इनायत से संभालें या यदि यह एक स्वीकार्य इनपुट है, तो एक अपवाद न फेंकें क्योंकि वे महंगे हैं। इसे अच्छे डिफॉल्ट्स के साथ ऑपरेशन करके या किसी भी ऑपरेशन (जैसे कोई अपडेट आवश्यक नहीं) के द्वारा नियंत्रित करें।

अंत में, स्थिति को संभालने के लिए कॉलर की क्षमता की उपेक्षा न करें। उन्हें अधिक विशिष्ट अपवाद देकर, ArgumentExceptionवे इस त्रुटि को अधिक सामान्य से पहले संभालने के लिए इस तरह से अपने प्रयास / पकड़ का निर्माण कर सकते हैं NullReferenceExceptionजो किसी भी अन्य कारणों से होने वाली किसी भी संख्या के कारण हो सकता है, जैसे कि एक कंस्ट्रक्टर चर को शुरू करने में विफलता।


1

चेक यह स्पष्ट करता है कि क्या चल रहा है, लेकिन वास्तविक समस्या इस तरह के कोड के साथ आती है (उदाहरण के लिए):

public void DoSomething(Foo someOtherObject, ISomeInterface someObject)
{
    someOtherObject.DoThisOrThat(this, someObject);
}

यहाँ एक कॉल चेन शामिल है और बिना किसी शून्य चेक के साथ आप केवल कुछ ओओऑथरऑबजेक्ट में त्रुटि देखते हैं और न कि जहां समस्या पहले प्रकट हुई थी - जिसका तात्पर्य है समय बर्बाद डिबगिंग या कॉल स्टैक की व्याख्या करना।

सामान्य तौर पर यह इस तरह की चीज़ों के साथ संगत होना बेहतर होता है और हमेशा अशक्त चेक को जोड़ते हैं - जिससे स्पॉट करना आसान हो जाता है यदि कोई मामला-दर-मामला आधार पर चुनने और चुनने के बजाय गायब है (यह मानते हुए कि आप जानते हैं कि अशक्त है हमेशा अमान्य)।


1

विचार करने का एक अन्य कारण यह है कि क्या अशक्त वस्तु के उपयोग से पहले कुछ प्रसंस्करण होता है?

मान लें कि आपके पास संबद्ध कंपनी ID (Cid) और व्यक्ति ID (Pid) की डेटा फ़ाइल है। इसे संख्या जोड़े की एक धारा के रूप में सहेजा गया है:

Cid Pid Cid Pid Cid पीआईडी ​​Cid Pid Cid Pid

और यह VB फ़ंक्शन फ़ाइल में रिकॉर्ड लिखते हैं:

Sub WriteRecord(Company As CompanyInfo, Person As PersonInfo)
    Using File As New StringWriter(DataFileName)
        File.Write(Company.ID)
        File.Write(Person.ID)
    End Using
End Sub

यदि Personएक अशक्त संदर्भ है, तो लाइन File.Write(Person.ID)एक अपवाद फेंक देगी। सॉफ़्टवेयर अपवाद को पकड़ सकता है और पुनर्प्राप्त कर सकता है, लेकिन यह एक समस्या छोड़ देता है। एक कंपनी आईडी एक संबंधित व्यक्ति आईडी के बिना लिखा गया है। यदि वास्तव में, जब आप अगली बार इस फ़ंक्शन को कॉल करते हैं, तो आपकी कंपनी एक कंपनी आईडी डालने जा रही है जहां पिछले व्यक्ति आईडी की उम्मीद थी। साथ ही उस रिकॉर्ड के गलत होने के बाद, प्रत्येक बाद के रिकॉर्ड में एक व्यक्ति आईडी होगा जिसके बाद एक कंपनी आईडी होगी, जो कि गलत तरीका है।

Cid Pid Cid पीआईडी Cid Cid Pid Cid पीआईडी ​​Cid

फ़ंक्शन की शुरुआत में मापदंडों को मान्य करके, आप किसी भी प्रसंस्करण को रोकने के लिए रोकते हैं जब विधि को विफल करने की गारंटी दी जाती है।

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