C # आपको 'अशक्त' करने की अनुमति क्यों देता है?


85

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

इसकी अनुमति क्यों है?

throw null;

इस स्निपेट में, शुक्र है कि 'पूर्व' अशक्त नहीं है, लेकिन क्या यह कभी हो सकता है?

try
{
  throw null;
}
catch (Exception ex)
{
  //can ex ever be null?

  //thankfully, it isn't null, but is
  //ex is System.NullReferenceException
}

8
क्या आप सुनिश्चित हैं कि आप अपने स्वयं के थ्रो के ऊपर फेंके गए .NET अपवाद (शून्य संदर्भ) को नहीं देख रहे हैं?
21

4
आपको लगता है कि संकलक कम से कम "सीधे नल फेंकने" की कोशिश करने के बारे में चेतावनी देगा।
एंडी व्हाइट

नहीं मुझे यकीन नहीं है ढांचा बहुत अच्छी तरह से मेरी वस्तु के साथ कुछ करने की कोशिश कर किया जा सकता है और जब यह रिक्त है, ढांचे के एक "अशक्त संदर्भ अपवाद" फेंकता है .. लेकिन अंत में, मुझे यकीन है कि "ex" कभी नहीं हो सकता अशक्त होना चाहता हूँ
चुटकुले

1
@ ऑंडी: एक चेतावनी लैंग्वेज में अन्य स्थितियों के लिए समझ में आ सकती है, लेकिन इसके लिए throw, एक बयान जिसका उद्देश्य पहली जगह में एक अपवाद फेंकना है, एक चेतावनी बहुत अधिक मूल्य नहीं जोड़ती है।
मेहरदाद आफश्री

@ मेहरदाद - हाँ, लेकिन मुझे संदेह है कि यदि कोई भी डेवलपर जानबूझकर "नल" फेंक देगा, और एक NullReferenceException देखना चाहता है। हो सकता है कि यह एक पूर्ण कथन में एक गलत = तुलना की तरह एक पूर्ण बिल्ड त्रुटि हो।
एंडी व्हाइट

जवाबों:


96

क्योंकि भाषा विनिर्देश System.Exceptionवहाँ प्रकार की अभिव्यक्ति की उम्मीद करता है (इसलिए, nullउस संदर्भ में एक मान्य है) और इस अभिव्यक्ति को गैर-अशक्त होने के लिए प्रतिबंधित नहीं करता है। सामान्य तौर पर, ऐसा कोई तरीका नहीं है जिससे यह पता लगाया जा सके कि उस अभिव्यक्ति का मूल्य है nullया नहीं। यह रुकने की समस्या को हल करना होगा। रनटाइम को nullवैसे भी मामले से निपटना होगा । देख:

Exception ex = null;
if (conditionThatDependsOnSomeInput) 
    ex = new Exception();
throw ex; 

वे निश्चित रूप से, nullशाब्दिक को फेंकने के विशिष्ट मामले को अमान्य बना सकते हैं, लेकिन इससे बहुत मदद नहीं मिलेगी, इसलिए स्पेसिफिकेशन को कम क्यों करें और थोड़े से लाभ के लिए निरंतरता को कम करें?

अस्वीकरण (इससे पहले कि मैं एरिक लिपर्ट द्वारा थप्पड़ मारा जाता हूं): इस डिजाइन निर्णय के पीछे तर्क के बारे में मेरी अपनी अटकलें हैं। बेशक, मैं डिजाइन मीटिंग में नहीं गया हूं;)


आपके दूसरे प्रश्न का उत्तर, कि क्या कैच क्लॉज़ के भीतर एक अभिव्यक्ति चर पकड़ा जा सकता है, कभी भी अशक्त हो सकता है: जबकि C # विनिर्देश इस बारे में चुप है कि क्या अन्य भाषाएं nullप्रचारित करने के लिए अपवाद का कारण बन सकती हैं , यह इस तरह परिभाषित करता है कि अपवाद प्रचारित हैं:

अपवाद के लिए उपयुक्त हैंडलर का पता लगाने के लिए कैच क्लॉज़, यदि कोई हो, उपस्थिति के क्रम में जांच की जाती है। पहला कैच क्लॉज जो अपवाद प्रकार को निर्दिष्ट करता है या एक आधार प्रकार के अपवाद प्रकार को मैच माना जाता है। एक सामान्य कैच क्लॉज को किसी भी अपवाद प्रकार के लिए एक मैच माना जाता है। [...]

के लिए null, बोल्ड स्टेटमेंट गलत है। इसलिए, जबकि विशुद्ध रूप से सी # कल्पना कहती है, हम यह नहीं कह सकते कि अंतर्निहित रनटाइम कभी भी अशक्त नहीं होगा, हम यह सुनिश्चित कर सकते हैं कि अगर ऐसा है, तो भी यह केवल सामान्य catch {}क्लॉज द्वारा नियंत्रित किया जाएगा ।

सीएलआई पर C # कार्यान्वयन के लिए, हम ECMA 335 विनिर्देश का उल्लेख कर सकते हैं। वह दस्तावेज़ सभी अपवादों को परिभाषित करता है कि सीएलआई आंतरिक रूप से फेंकता है (जिनमें से कोई भी नहीं null) और उल्लेख करता है कि उपयोगकर्ता द्वारा परिभाषित अपवाद ऑब्जेक्ट्स को throwनिर्देश द्वारा फेंक दिया गया है । उस निर्देश का विवरण वस्तुतः C # throwकथन के समान है (सिवाय इसके कि वह वस्तु के प्रकार को प्रतिबंधित न करे System.Exception):

विवरण:

throwअनुदेश अपवाद वस्तु (प्रकार फेंकता Oस्टैक पर) और ढेर खाली। अपवाद तंत्र के विवरण के लिए, विभाजन I देखें।
[नोट: जबकि सीएलआई किसी भी वस्तु को फेंकने की अनुमति देता है, सीएलएस एक विशिष्ट अपवाद वर्ग का वर्णन करता है जिसका उपयोग भाषा अंतर के लिए किया जाएगा। नोट नोट]

अपवाद:

System.NullReferenceExceptionअगर फेंक दिया जाता है objहै null

शुद्धता:

सही CIL यह सुनिश्चित करता है कि ऑब्जेक्ट हमेशा या तो nullऑब्जेक्ट रेफ़रेंस (यानी, प्रकार का O) हो।

मेरा मानना ​​है कि ये निष्कर्ष निकालने के लिए पर्याप्त हैं अपवाद कभी नहीं पकड़े गए हैं null


मुझे लगता है कि यह सबसे अच्छा हो सकता है जैसे कि स्पष्ट वाक्यांशों पर रोक लगाने के लिए throw null;
FrustratedWithFormsDesigner

7
वास्तव में, यह पूरी तरह से संभव है (सीएलआर में) किसी वस्तु को फेंकने के लिए जो कि System.Exception से विरासत में नहीं आता है। जहाँ तक मुझे पता है आप इसे C # में नहीं कर सकते, लेकिन यह IL, C ++ / CLR, आदि के माध्यम से किया जा सकता है । अधिक जानकारी के लिए देखें msdn.microsoft.com/en-us/library/ms404228.aspx
टेक्नोफाइल

@technophile: हाँ। मैं यहाँ भाषा के बारे में बात कर रहा हूँ। C # में, अन्य प्रकार के अपवाद को फेंकना संभव नहीं है, लेकिन सामान्य catch { }क्लॉज का उपयोग करके इसे पकड़ना संभव है ।
मेहरदाद अफश्री

1
हालांकि यह समझ में नहीं आता है कि कंपाइलर throwकिसके तर्क को मानने से इंकार कर सकता है, यह एक अशक्त मूल्य हो सकता है, जो कि throw nullकानूनी नहीं होगा। एक संकलक जोर दे सकता है कि एक throwतर्क में एक समझदार वर्ग प्रकार है। (System.InvalidOperationException)nullसंकलित समय पर एक अभिव्यक्ति की तरह मान्य होना चाहिए (इसे निष्पादित करना चाहिए NullReferenceException), लेकिन इसका मतलब यह नहीं है कि एक अनपेक्षित nullस्वीकार्य होना चाहिए।
सुपर

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

29

जाहिर है, आप अशक्त फेंक सकते हैं, लेकिन यह अभी भी कहीं अपवाद में बदल गया है।

nullएक (पूरी तरह से असंबंधित) अशक्त संदर्भ अपवाद में एक वस्तु परिणाम फेंकने का प्रयास ।

यह पूछना कि आपको फेंकने की अनुमति क्यों nullहै, यह पूछना कि आपको ऐसा करने की अनुमति क्यों है:

object o = null;
o.ToString();

5

यहाँ से लिया गया :

यदि आप इस अभिव्यक्ति का उपयोग अपने C # कोड में करते हैं तो यह NullReferenceException को फेंक देगा। ऐसा इसलिए है क्योंकि फेंक-स्टेटमेंट को इसके एकल पैरामीटर के रूप में अपवाद की वस्तु की आवश्यकता है। लेकिन यह बहुत ही वस्तु मेरे उदाहरण में शून्य है।


5

हालांकि C # में null को फेंकना संभव नहीं हो सकता है क्योंकि थ्रो उस का पता लगा लेगा और इसे NullReferenceException में बदल देगा, यह null प्राप्त करना संभव है ... मैं अभी वह प्राप्त कर रहा हूं, जो मेरे कैच का कारण बनता है (जो नहीं था एक अशक्त संदर्भ अपवाद का अनुभव करने के लिए 'पूर्व' अशक्त होने की उम्मीद करना, जिसके परिणामस्वरूप मेरा ऐप मर जाता है (क्योंकि यह आखिरी कैच था)।

इसलिए, जब हम C # से नल नहीं फेंक सकते, तो netherworld null को फेंक सकता है, इसलिए इसे प्राप्त करने के लिए आपका सबसे बाहरी कैच (अपवाद पूर्व) बेहतर होगा। सिर्फ आपकी जानकारी के लिए।


3
दिलचस्प। क्या आप कुछ कोड पोस्ट कर सकते हैं या हो सकता है कि नीचे अपनी गहराई में बैठे ऐसा कर रहे हों?
पीटर लिलीवॉल्ड

मैं आपको बता नहीं सकता कि क्या यह सीएलआर बग है ... यह नीचे ट्रैक करना मुश्किल है कि .NET की हिम्मत क्या हुई है और आपको कॉल स्टैक या किसी अन्य सुराग के साथ अपवाद क्यों नहीं मिलता है। मुझे सिर्फ इतना पता है कि मेरे सबसे बाहरी कैच का अब उपयोग करने से पहले अशक्त अपवाद तर्क की जाँच करें।
ब्रायन कैनेडी

3
मुझे संदेह है कि यह सीएलआर बग है, या खराब अपरिवर्तनीय कोड के कारण है। सही CIL केवल एक गैर-अशक्त वस्तु, या अशक्त (जो NullReferenceException बन जाती है) को फेंक देगी।
डेमी

मैं एक सेवा का उपयोग भी कर रहा हूं जो एक अशक्त अपवाद लौटा रही है। क्या आपने कभी पता लगाया कि शून्य अपवाद कैसे फेंका जा रहा था?
themiDdlest 17

2

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


2

जवाब देने की कोशिश कर रहा है "..अचानक 'पूर्व' शून्य नहीं है, लेकिन क्या यह कभी हो सकता है?"

चूँकि हम यकीनन ऐसे अपवादों को नहीं फेंक सकते जो कि अशक्त है, एक कैच क्लॉज को भी एक अपवाद नहीं पकड़ना पड़ेगा जो कि अशक्त हो। इस प्रकार, पूर्व कभी भी अशक्त नहीं हो सकता है।

अब मैं देखता हूं कि यह प्रश्न वास्तव में पहले से ही पूछा गया है


@ ब्रायन कैनेडी ने ऊपर अपनी टिप्पणी में हमें बताया कि हम अशक्त को पकड़ सकते हैं।
प्रोफके डे

@ Tvde1 - मुझे लगता है कि यहाँ अंतर यह है कि, हाँ, आप निष्पादित कर सकते हैं throw null। लेकिन यह एक अपवाद नहीं है जो अशक्त है । बल्कि, क्योंकि throw nullएक अशक्त संदर्भ पर तरीकों को लागू करने की कोशिश करता है, यह बाद में रनटाइम को एक गैर-शून्य उदाहरण को फेंकने के लिए मजबूर करता है NullReferenceException
पीटर लिलवॉल्ड

1

याद रखें कि अपवाद में विवरण शामिल हैं जहां अपवाद को फेंक दिया गया है। देखने वाले के रूप में कंस्ट्रक्टर को यह पता नहीं है कि उसे कहां फेंकना है, तो यह केवल यह समझ में आता है कि फेंक विधि उन विवरणों को उस बिंदु पर वस्तु में इंजेक्ट करती है जो फेंक रहा है। दूसरे शब्दों में CLR डेटा को शून्य में इंजेक्ट करने का प्रयास कर रहा है, जो NullReferenceException को ट्रिगर करता है।

निश्चित नहीं है कि यह वास्तव में क्या हो रहा है, लेकिन यह घटना की व्याख्या करता है।

यह सच है (और मुझे लगता है कि एक बेहतर तरीका से बाहर निकलना करने के लिए शून्य से कम हो सकता है नहीं लगता है;), इसका मतलब यह है कि पूर्व संभवत: अशक्त नहीं हो सकता है।


0

पुराने c # में:

इस वाक्यविन्यास पर विचार करें:

public void Add<T> ( T item ) => throw (hashSet.Add ( item ) ? null : new Exception ( "The item already exists" ));

मुझे लगता है कि यह इससे छोटा है:

public void Add<T> ( T item )
{
    if (!hashSet.Add ( item ))
        throw new Exception ( "The item already exists" );
}

यह हमें क्या बताता है?
जन्म

संयोग से, मुझे यकीन नहीं है कि आपकी परिभाषा छोटी है, लेकिन आपके दूसरे उदाहरण में कम अक्षर हैं।
जन्म

@bornfromanegg नंबर 1 इनबिल्ड नहीं है, इसलिए यह निश्चित रूप से छोटा है। मैं जो कहना चाह रहा था, वह यह है कि स्थिति के आधार पर आप एक त्रुटि फेंक सकते हैं। परंपरागत रूप से, यू 2 उदाहरण की तरह होगा, लेकिन चूंकि "थ्रो नल" कुछ भी नहीं फेंकता है, यू 1 उदाहरण की तरह दिखने के लिए दूसरा उदाहरण इनलाइन कर सकता है। इसके अलावा, 1 उदाहरण में 8 अक्षर 2 से कम हैं
अरूटुन एनफेंझजान

"थ्रो नल" एक NullReference अपवाद को फेंकता है। जिसका अर्थ है कि आपका पहला उदाहरण हमेशा एक अपवाद को फेंक देगा ।
जन्म

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