हम इन अपवादों को क्यों नहीं फेंक रहे हैं?


111

मैं इस MSDN पृष्ठ पर आया हूं जो बताता है:

अपवाद , SystemException , NullReferenceException , या IndexOutOfRangeException को अपने ही स्रोत कोड से जानबूझकर न फेंके ।

दुर्भाग्य से, यह समझाने की जहमत नहीं उठाता कि क्यों। मैं कारणों का अनुमान लगा सकता हूं लेकिन मुझे उम्मीद है कि इस विषय पर कोई और अधिक अधिकारी अपनी अंतर्दृष्टि प्रदान कर सकता है।

पहले दो कुछ स्पष्ट समझ में आते हैं, लेकिन बाद के दो ऐसे लगते हैं जैसे आप नौकरी करना चाहते हैं (और वास्तव में, मेरे पास)।

इसके अलावा, क्या इन एकमात्र अपवादों से बचना चाहिए? यदि अन्य हैं, तो वे क्या हैं और क्यों, उन्हें भी, परहेज करना चाहिए?


22
से msdn.microsoft.com/en-us/library/ms182338.aspx : आप इस तरह के अपवाद या एक पुस्तकालय या ढांचे में SystemException के रूप में एक सामान्य अपवाद प्रकार, फेंक, तो यह उपभोक्ताओं बलों सभी अपवादों को पकड़ने के लिए, अज्ञात अपवाद कि वे करते हैं सहित संभालना नहीं जानता।
हेनरिक

3
आप एक NullReferenceException क्यों फेंकेंगे?
रिक

5
@ रिक: NullArgumentExceptionजिसके समान कुछ लोग दोनों को भ्रमित कर सकते हैं।
मोसमेल बेन धौ

2
@Rik विस्तार के तरीकों, मेरा उत्तर के अनुसार
मार्क Gravell

3
एक और जिसे आप फेंकना नहीं चाहिए वह हैApplicationException
मैथ्यू वॉटसन

जवाबों:


98

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

यही कारण लागू भी होता है SystemException। यदि आप व्युत्पन्न प्रकारों की सूची को देखते हैं, तो आप बहुत भिन्न अर्थों के साथ अन्य अपवादों की एक बड़ी संख्या देख सकते हैं।

NullReferenceExceptionऔर IndexOutOfRangeExceptionएक अलग तरह के हैं। अब ये बहुत विशिष्ट अपवाद हैं, इसलिए इन्हें फेंकना ठीक हो सकता है। हालाँकि, आप अभी भी इन्हें फेंकना नहीं चाहेंगे, क्योंकि उनका आमतौर पर मतलब होता है कि आपके तर्क में कुछ वास्तविक गलतियाँ हैं। उदाहरण के लिए अशक्त संदर्भ अपवाद का अर्थ है कि आप किसी वस्तु के सदस्य तक पहुँचने का प्रयास कर रहे हैं null। यदि आपके कोड में यह संभावना है, तो आपको हमेशा स्पष्ट रूप से जांच करनी चाहिए nullऔर इसके बजाय एक अधिक उपयोगी अपवाद फेंकना चाहिए (उदाहरण के लिए ArgumentNullException)। इसी तरह, IndexOutOfRangeExceptionतब होता है जब आप एक अमान्य सूचकांक (सरणियों पर - सूचियों पर नहीं) तक पहुँचते हैं। आपको हमेशा यह सुनिश्चित करना चाहिए कि आप पहली बार में ऐसा न करें और पहले एक सरणी जैसे उदाहरण की सीमाओं की जांच करें।

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

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

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


3
तीसरा हिस्सा मेरे लिए बहुत कम मायने रखता है। निश्चित रूप से, आपको इन त्रुटियों को शुरू करने से बचने की बजाय बचना चाहिए, लेकिन जब आप उदाहरण के लिए एक IListकार्यान्वयन लिखते हैं , तो अनुरोधित सूचकांकों को प्रभावित करना आपकी शक्ति में नहीं है, यह एक सूचकांक अमान्य होने पर कॉलर की तर्क गलती है, और आप केवल उन्हें सूचित कर सकते हैं एक उपयुक्त अपवाद को फेंककर इस तर्क त्रुटि का। क्यों IndexOutOfRangeExceptionउचित नहीं है?

7
@delnan यदि आप कार्यान्वित कर रहे हैं IList, तो आप इंटरफ़ेस प्रलेखन का सुझाव देते ArgumentOutOfRangeExceptionहुए फेंक देंगे । सरणियों के लिए है, और जहां तक ​​मुझे पता है, आप सरणियों को फिर से लागू नहीं कर सकते। IndexOutOfRangeException
प्रहार

2
यह भी कुछ हद तक संबंधित हो सकता है, NullReferenceExceptionआमतौर पर आंतरिक रूप से एक विशेष मामले के रूप में फेंक दिया जाता है AccessViolationException(IIRC परीक्षण कुछ ऐसा है cmp [addr], addr, अर्थात। यह पॉइंटर को रोकने की कोशिश करता है और यदि यह एक्सेस उल्लंघन के साथ विफल होता है, तो यह एनआरई और एवीई के बीच अंतर को संभालता है। जिसके परिणामस्वरूप बाधित हैंडलर)। तो अर्थ संबंधी कारणों के अलावा, इसमें कुछ धोखा भी शामिल है। यह nullमैन्युअल रूप से चेक करने से आपको हतोत्साहित करने में मदद कर सकता है जब यह मददगार न हो - यदि आप वैसे भी एनआरई को फेंकने जा रहे हैं, तो .NET को इसकी अनुमति क्यों नहीं दें?
लुआॅन

आपके अंतिम कथन के संबंध में, कस्टम अपवादों के बारे में: मुझे ऐसा करने की आवश्यकता कभी महसूस नहीं हुई। शायद मुझे कुछ याद आ रहा है। किन परिस्थितियों में किसी को फ्रेमवर्क से कुछ के बदले एक कस्टम अपवाद प्रकार को शिल्प करने की आवश्यकता होगी?
DonBoitnott

1
ठीक है, छोटे अनुप्रयोगों के लिए इसकी आवश्यकता नहीं हो सकती है। लेकिन जैसे ही आप कुछ और अधिक जटिल बनाते हैं, जहां अलग-अलग हिस्से स्वतंत्र "घटकों" के रूप में काम करते हैं, यह अक्सर कस्टम त्रुटि स्थितियों के लिए कस्टम अपवाद पेश करने के लिए समझ में आता है। उदाहरण के लिए, यदि आपके पास कुछ एक्सेस कंट्रोल लेयर है, और आप कुछ सेवा निष्पादित करने का प्रयास करते हैं, हालांकि आप ऐसा करने के लिए अधिकृत नहीं हैं, तो आप एक कस्टम "एक्सेस अस्वीकृत अपवाद" या कुछ और फेंक सकते हैं। या यदि आपके पास कोई पार्सर है जो किसी फ़ाइल को पार्स करता है, तो उपयोगकर्ता को वापस रिपोर्ट करने के लिए आपकी अपनी पार्सर त्रुटियां हो सकती हैं।
प्रहार

36

मुझे संदेह है कि पिछले 2 के साथ इरादे इनबिल्ट अपवादों के साथ भ्रम को रोकने के लिए है जिनका एक अपेक्षित अर्थ है। हालाँकि, मेरी राय है कि यदि आप अपवाद के सटीक इरादे को संरक्षित कर रहे हैं : यह सही है throw। उदाहरण के लिए, यदि आप एक कस्टम संग्रह लिख रहे हैं, तो यह उपयोग करने के लिए पूरी तरह से उचित है IndexOutOfRangeException- स्पष्ट और अधिक विशिष्ट, IMO, की तुलना में ArgumentOutOfRangeException। और जबकि List<T>बाद वाला चुन सकते हैं, बीसीएल में कम से कम 41 स्थान (परावर्तक के शिष्टाचार) हैं (एरे को शामिल नहीं) जो बीस्पोक फेंकते हैं IndexOutOfRangeException- जिनमें से कोई भी "निम्न स्तर" विशेष छूट के लायक नहीं है। तो हाँ, मुझे लगता है कि आप बस यह तर्क दे सकते हैं कि गाइडलाइन मूर्खतापूर्ण है। इसी तरह,NullReferenceException विस्तार विधियों में उपयोगी है - यदि आप उस शब्दार्थ को संरक्षित करना चाहते हैं:

obj.SomeMethod(); // this is actually an extension method

NullReferenceExceptionजब objहै तब फेंकता है null


2
"यदि आप अपवाद के सटीक इरादे को संरक्षित कर रहे हैं" - तो निश्चित रूप से अगर ऐसा है तो अपवाद को आपके बिना परीक्षण किए बिना ही फेंक दिया जाएगा? और अगर आपने इसके लिए पहले ही परीक्षण कर लिया है, तो यह वास्तव में अपवाद नहीं है?
पुगफगली

5
@PugFugly विस्तार विधि उदाहरण को देखने के लिए 2 सेकंड लेते हैं: नहीं, इसके लिए परीक्षण किए बिना आपको फेंका नहीं जाएगा। यदि आपको SomeMethod()सदस्य अभिगमन करने की आवश्यकता नहीं है, तो इसे बाध्य करना गलत है। इसी तरह: बीसीएल में 41 स्थानों के साथ उस बिंदु को उठाएं जो कस्टम बनाते हैं IndexOutOfRangeException, और 16 जगहें जो कस्टम बनाती हैंNullReferenceException
मार्क ग्रेवेल

16
मैं तर्क दूंगा कि अभी भी एक एक्सटेंशन पद्धति को एक के ArgumentNullExceptionबजाय फेंक देना चाहिए NullReferenceException। यहां तक ​​कि अगर विस्तार के तरीकों से सिंटैक्टिक शुगर समान सिंटैक्स को सामान्य सदस्य पहुंच के रूप में अनुमति देता है, तो भी यह बहुत अलग तरीके से काम करता है। और इससे एनआरई प्राप्त MyStaticHelpers.SomeMethod(obj)करना गलत होगा।
प्रहार

1
@PugFugly BCL "बेस क्लास लाइब्रेरी" है, मूल रूप से .NET में मूल सामग्री है।
प्रहार

1
@PugFugly: ऐसे कई परिदृश्य हैं जहां किसी स्थिति का पहले से पता लगाने में विफल रहने के परिणामस्वरूप अपवाद को "असुविधाजनक" समय पर फेंक दिया जाएगा। यदि कोई ऑपरेशन सफल नहीं हो रहा है, तो एक अपवाद को जल्दी फेंकना ऑपरेशन शुरू करने से बेहतर है, आधे रास्ते से गुजरना, और फिर परिणामस्वरूप आंशिक रूप से संसाधित गंदगी को साफ करना।
सुपरकैट

5

जैसा कि आप बताते हैं, आर्टिकल क्रिएट एंड थ्रोइंग एक्सेप्शन (C # प्रोग्रामिंग गाइड) विषय के तहत चीजें थ्रोइंग एक्ससेप्शन से बचने के लिए , Microsoft वास्तव System.IndexOutOfRangeExceptionमें एक अपवाद प्रकार के रूप में सूची बनाता है जिसे जानबूझकर अपने स्रोत कोड से नहीं फेंकना चाहिए।

इसके विपरीत, हालांकि, लेख थ्रो (C # संदर्भ) में , Microsoft अपने स्वयं के दिशानिर्देशों का उल्लंघन करता है। यहाँ एक विधि है जिसे Microsoft ने अपने उदाहरण में शामिल किया है:

static int GetNumber(int index)
{
    int[] nums = { 300, 600, 900 };
    if (index > nums.Length)
    {
        throw new IndexOutOfRangeException();
    }
    return nums[index];
}

इसलिए, Microsoft स्वयं सुसंगत नहीं हो रहा है क्योंकि यह IndexOutOfRangeExceptionउसके प्रलेखन में फेंकने का प्रदर्शन करता है throw!

यह मुझे विश्वास दिलाता है कि कम से कम के मामले में IndexOutOfRangeException, ऐसे अवसर हो सकते हैं जहां प्रोग्रामर द्वारा उस अपवाद प्रकार को फेंक दिया जा सकता है और एक स्वीकार्य अभ्यास माना जा सकता है।


1

जब मैंने आपका प्रश्न पढ़ा, तो मैंने खुद से पूछा कि किन परिस्थितियों में कोई व्यक्ति अपवाद प्रकार फेंकना चाहेगा NullReferenceException, InvalidCastExceptionया ArgumentOutOfRangeException

मेरी राय में, उन अपवाद प्रकारों में से एक का सामना करते समय, मैं (डेवलपर) इस अर्थ में चेतावनी से चिंतित महसूस करता हूं कि कंपाइलर मुझसे बात कर रहा है। तो, आपको (डेवलपर) ऐसे अपवाद प्रकारों को फेंकने की अनुमति देना (संकलक) जिम्मेदारी बेचने के बराबर है। उदाहरण के लिए, यह सुझाव देता है कि कंपाइलर को अब डेवलपर को यह तय करने की अनुमति देनी चाहिए कि कोई वस्तु है या नहीं null। लेकिन ऐसा दृढ़ संकल्प बनाना वास्तव में कंपाइलर का काम होना चाहिए।

पुनश्च: 2003 के बाद से मैं अपने स्वयं के अपवाद विकसित कर रहा हूं, इसलिए मैं उन्हें अपनी इच्छानुसार फेंक सकता हूं। मुझे लगता है कि ऐसा करना सबसे अच्छा अभ्यास माना जाता है।


अच्छे अंक। हालांकि, मुझे लगता है कि यह कहना अधिक सटीक होगा कि प्रोग्रामर को .NET फ्रेमवर्क रनटाइम को इस प्रकार के अपवादों को फेंकने देना चाहिए (और यह कि प्रोग्रामर को उन्हें उचित तरीके से संभालना चाहिए)।
डेविडआरआर

0

चर्चा के बारे में लाना NullReferenceExceptionऔर IndexOutOfBoundsExceptionएक तरफ:

पकड़ने और फेंकने का क्या System.Exception। मैंने अपने कोड में इस प्रकार के अपवाद को बहुत फेंक दिया है और मैं इसके द्वारा कभी भी खराब नहीं हुआ। इसी तरह, बहुत बार मैं अनिर्दिष्ट Exceptionप्रकार पकड़ता हूं , और यह मेरे लिए बहुत अच्छा काम करता है। तो, ऐसा क्यों है?

आमतौर पर उपयोगकर्ता तर्क देते हैं, कि उन्हें त्रुटि कारणों को भेद करने में सक्षम होना चाहिए। मेरे अनुभव से, ऐसी बहुत कम स्थितियाँ हैं जहाँ आप अलग-अलग तरह के अपवादों को संभालना चाहते हैं। उन मामलों के लिए, जहां आप उपयोगकर्ताओं से प्रोग्रामेटिक रूप से त्रुटियों को संभालने की अपेक्षा करते हैं, आपको अधिक विशिष्ट अपवाद प्रकार फेंकना चाहिए। अन्य मामलों के लिए, मैं सामान्य सर्वोत्तम अभ्यास दिशानिर्देश से आश्वस्त नहीं हूं।

इसलिए, फेंकने के बारे में Exceptionमुझे सभी मामलों में इसे प्रतिबंधित करने का कोई कारण नहीं दिखता है।

संपादित करें: MSDN पृष्ठ से भी:

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

विभिन्न अपवाद प्रकारों के लिए व्यक्तिगत तर्क के साथ ओवरडोइंग कैच क्लॉस सर्वश्रेष्ठ अभ्यास नहीं हैं, या तो।


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

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