क्या अशक्त संदर्भ अपवाद को फेंकना किसी भी () * नहीं * की अपेक्षा अनुचित है?


41

जब आप कोई एक्सटेंशन विधि आप कर सकते हैं बनाने के लिए, निश्चित रूप से, उस पर फोन null.लेकिन, एक उदाहरण विधि कॉल के विपरीत, अशक्त पर बुला नहीं करता है एक फेंक NullReferenceException-> आप की जाँच करें और इसे मैन्युअल रूप से फेंकने के लिए की है।

लाइनक एक्सटेंशन पद्धति के कार्यान्वयन के लिए Any()Microsoft ने फैसला किया कि उन्हें ArgumentNullException( https://github.com/dotnet/corefx/blob/master/src/System/inst/src/Src/System/Linq/Anyx.cs ) फेंकना चाहिए ।

यह मुझे लिखना पड़ता है if( myCollection != null && myCollection.Any() )

क्या मैं इस कोड के ग्राहक के रूप में गलत हूं, यह उम्मीद करने के लिए कि उदाहरण के लिए ((int[])null).Any()वापस आ जाना चाहिए false?


41
C # 6 में, यदि आप (myCollection .Any () == true) पर अपने चेक को सरल कर सकते हैं
17 का 26

5
यहां तक ​​कि एफ # में, जो वास्तव में अन्य .NET भाषाओं, null |> Seq.isEmptyफेंकता के साथ इंटरऑपरेबिलिटी को छोड़कर नल का उपयोग नहीं करता है System.ArgumentNullException: Value cannot be null। उम्मीद की जा रही है कि आप किसी ऐसी चीज़ के लिए अपरिभाषित मूल्यों को पारित नहीं करेंगे, जो मौजूद होने की उम्मीद है, इसलिए यह अभी भी एक अपवाद है जब आपके पास एक अशक्त है। यदि यह आरंभीकरण की बात है, तो मैं एक के बजाय एक खाली अनुक्रम के साथ शुरू करूंगा null
आरोन एम। एशबाक

21
इसीलिए आपको nullसंग्रह से निपटते समय नहीं लौटना चाहिए, बल्कि उन मामलों में एक खाली संग्रह का उपयोग करना चाहिए ।
बकुरीउ

31
वैसे यह पहली जगह में अशक्त क्यों है? आप रिक्त नहीं के रूप में गिना जाना चाहते हैं, क्योंकि यह खाली नहीं है, यह पूरी तरह से कुछ अलग है। हो सकता है कि आप चाहते हैं कि इसे आपके मामले में खाली गिना जाए, लेकिन भाषा में उस तरह की चीजों को शामिल करने से कीड़े हो जाते हैं।
user253751

22
मुझे ध्यान देना चाहिए कि हर एक LINQ विधि एक अशक्त तर्क पर फेंकता है। Anyसुसंगत है।
सेबेस्टियन रेडल

जवाबों:


157

मेरे पास एक बैग है जिसमें पाँच आलू हैं। क्या .Any()बैग में आलू हैं?

" हाँ ," आप कहते हैं।<= true

मैं सभी आलू बाहर निकालता हूं और उन्हें खाता हूं। क्या .Any()बैग में आलू हैं?

" नहीं ," आप कहते हैं।<= false

मैं बैग को पूरी तरह से आग में झोंक देता हूं। क्या .Any()अब बैग में आलू हैं?

" कोई बैग नहीं है ।"<= ArgumentNullException


3
लेकिन खाली तौर पर, बैग में आलू नहीं हैं? झूठी का मतलब है गलत ... (मैं असहमत नहीं हूं, सिर्फ एक दूसरा परिप्रेक्ष्य)।
डी। बेन नोबल

6
अधिक व्यावहारिक रूप से, कोई आपको अज्ञात स्रोत से एक बंद बॉक्स सौंपता है। क्या बॉक्स में बैग में कोई आलू है? मुझे केवल 2 परिदृश्यों में दिलचस्पी है - ए) बॉक्स में एक बैग है जिसमें आलू हैं, या बी) बॉक्स में कोई आलू और / या कोई बैग नहीं हैं। शब्दार्थ, हाँ, शून्य और रिक्त के बीच अंतर है, लेकिन 99% समय मुझे ध्यान नहीं है।
die thieben

6
आपने पाँच कच्चे आलू खाए ?? तुरंत चिकित्सा की तलाश करें।
ओले

3
@ ओली ने उन्हें आग में पकाया, खाने से पहले और उस आग को बैग में डालने के लिए इस्तेमाल किया।
इस्माइल मिगुएल

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

52

सबसे पहले, ऐसा लगता है कि स्रोत कोड फेंक देगा ArgumentNullException, नहीं NullReferenceException

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

क्या मैं इस कोड के ग्राहक के रूप में गलत हूं, यह उम्मीद करने के लिए कि उदाहरण के लिए ((int[])null).Any()वापस आ जाना चाहिए false?

हाँ। सवाल जो Any()जवाब है "क्या इस संग्रह में कोई तत्व हैं?" यदि यह संग्रह मौजूद नहीं है, तो सवाल ही निरर्थक है; इसमें न तो कुछ हो सकता है और न ही कुछ हो सकता है, क्योंकि यह मौजूद नहीं है।


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

17
@ क्रिस वॉल्हर्ट: स्पष्ट रूप से एक सेट में खाली सेट हो सकता है; लेकिन आपको लगता है कि यह होना चाहिए { null }और { {} }समकक्ष होना चाहिए। मुझे वह आकर्षक लगती है; मैं इससे बिल्कुल संबंधित नहीं हो सकता।
बरबाद

9
चाहिए .Addएक पर nullसंग्रह किसी भी तरह भी हमारे लिए एक संग्रह बनाने के?
मैथ्यू

13
@ChrisWohlert "A एक खाली सेट है। B एक सेट है जिसमें तरबूज होता है। क्या खाली है? हाँ? B खाली है? नहीं, C खाली है? Uhhh ..."
user253751

16
पद्यात्मक बिंदु: यह ऐसा नहीं है, सेट सिद्धांत में, एक गैर-मौजूदा सेट एक खाली सेट है। खाली सेट मौजूद है, और कोई भी गैर-मौजूदा सेट यह नहीं है (और वास्तव में, यह कुछ भी नहीं है, क्योंकि यह मौजूद नहीं है)।
जेम्स_पिक

22

अशक्त का अर्थ है गुम सूचना, कोई तत्व नहीं।

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

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

यह भी देखें https://stackoverflow.com/questions/1191919/what-does-linq-return-when-the-results-are-empty


1
इसका nullमतलब यह नहीं है कि कोई तत्व एक समझदार सम्मेलन का उपयोग करने का मामला नहीं है । केवल मूल OLESTRINGS के बारे में सोचें, जहां यह वास्तव में इसका मतलब है।
डेडुप्लिकेटर

1
@Deduplicator, क्या आप Microsoft के ऑब्जेक्ट लिंकिंग और एंबेडिंग पर्चेंस के बारे में बात कर रहे हैं? यदि आपको याद है कि OLE '90 के दशक से है! वर्तमान में अधिक देखते हुए, कई आधुनिक भाषाएँ (C #, Java, Swift) नल के उपयोग को समाप्त / मिटाने के लिए सुविधाएं प्रदान कर रही हैं।
एरिक इद्दत

2
@ErikEidt वे ऐसा कर रहे हैं, भाग में, क्योंकि null"गुम सूचना" का मतलब नहीं है। nullएक भी सार्थक व्याख्या नहीं है। इसके बजाय, यह एक बात है कि आप इसे कैसे मानते हैं। nullकभी-कभी "गुम सूचना" के लिए, लेकिन "कोई तत्व नहीं" के लिए भी उपयोग किया जाता है, और "कोई त्रुटि उत्पन्न हुई" या "असंबद्ध" या "परस्पर विरोधी जानकारी" या कुछ मनमानी, तदर्थ बात के लिए भी।
डेरेक एल्किंस

-1। यह डेवलपर द्वारा किया गया निर्णय है, न कि अमूर्त सिद्धांतों द्वारा। null"अक्सर कोई डेटा नहीं है" का मतलब पूरी तरह से उपयोग किया जाता है। कभी-कभी समझ में आता है। अन्य बार, नहीं।
jpmc26

13

के अलावा अशक्त-सशर्त वाक्य रचना न दें अपने चर कभी रहते हैं:, इस समस्या को कम करने के लिए एक और तकनीक है null

एक फ़ंक्शन पर विचार करें जो एक संग्रह को एक पैरामीटर के रूप में स्वीकार करता है। यदि फ़ंक्शन के प्रयोजनों के लिए, nullऔर खाली समान हैं, तो आप यह सुनिश्चित कर सकते हैं कि इसमें nullशुरुआत में कभी भी शामिल न हों :

public MyResult DoSomething(int a, IEnumerable<string> words)
{
    words = words ?? Enumerable.Empty<string>();

    if (!words.Any())
    {
        ...

जब आप किसी अन्य विधि से संग्रह प्राप्त करते हैं तो आप ऐसा कर सकते हैं:

var words = GetWords() ?? Enumerable.Empty<string>();

(ध्यान दें कि ऐसे मामलों में जहां आपका किसी फ़ंक्शन पर नियंत्रण है GetWordsऔर nullखाली संग्रह के बराबर है, पहले स्थान पर खाली संग्रह को वापस करना बेहतर होगा।)

अब आप किसी भी ऑपरेशन को अपनी इच्छा से संग्रह पर कर सकते हैं। यह विशेष रूप से उपयोगी है यदि आपको कई ऑपरेशन करने की आवश्यकता होती है जो संग्रह होने पर विफल हो जाएगा null, और ऐसे मामलों में जहां आपको एक खाली गणना को ओवर-लूप करके या क्वेरी करके समान परिणाम मिलता है, यह ifपूरी तरह से शर्तों को समाप्त करने की अनुमति देगा ।


12

क्या मैं गलत हूँ, इस कोड के ग्राहक के रूप में, यह उम्मीद करने के लिए कि उदा ((int []) null)। किसी भी () को गलत नहीं लौटना चाहिए?

हां, केवल इसलिए कि आप C # में हैं और यह व्यवहार अच्छी तरह से परिभाषित और प्रलेखित है।

यदि आप अपनी खुद की लाइब्रेरी बना रहे थे, या यदि आप अलग-अलग अपवाद संस्कृति के साथ एक अलग भाषा का उपयोग कर रहे थे, तो झूठी उम्मीद करना अधिक उचित होगा।

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


15
यह 'मजबूती' अक्सर एक भ्रम है - अगर कोड जो सरणी उत्पन्न करता है तो बग या अन्य मुद्दे के कारण अप्रत्याशित रूप से NULLs उत्पन्न करना शुरू कर देता है, आपका 'मजबूत' कोड समस्या को छिपा देगा। यह समय पर उचित व्यवहार है, लेकिन एक सुरक्षित डिफ़ॉल्ट नहीं है।
GoatInTheMachine

1
@GoatInTheMachine - मैं इसके बारे में सहमत नहीं हूं कि यह एक सुरक्षित डिफ़ॉल्ट है, लेकिन आप सही हैं कि यह समस्या को छिपाता है और ऐसा व्यवहार कई बार अवांछनीय होता है। मेरे अनुभव में, समस्या को छिपाना (या अन्य कोड की समस्याओं को पकड़ने के लिए यूनिट परीक्षणों पर भरोसा करना) अप्रत्याशित अपवादों को फेंककर अपने ऐप को क्रैश करने से बेहतर है। मेरा वास्तव में मतलब है - यदि कॉलिंग कोड को नल में भेजने के लिए पर्याप्त रूप से तोड़ा जाता है, तो मौका क्या है जो वे अपवादों को ठीक से संभालते हैं?
तेलस्तान

10
अगर कुछ टूट गया है, चाहे वह मेरा कोड हो, किसी अन्य सहयोगी या ग्राहक का, मैं कोड को तुरंत विफल कर दूंगा और लोग इसके बारे में जानते थे कि यह एक अनिर्धारित मात्रा के लिए संभावित असंगत स्थिति में था। ऐसा करने में सक्षम होना निश्चित रूप से कभी-कभी एक लक्जरी है और हमेशा उचित नहीं है, लेकिन यह वह दृष्टिकोण है जो मुझे पसंद है।
GoatInTheMachine

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

8
कल्पना कीजिए कि आपके पास एक ऐसा सरणी है जो एक वेब अनुरोध के माध्यम से प्राप्त JSON दस्तावेज़ से पॉपुलेटेड है, और उत्पादन में आपके एपीआई के ग्राहकों में से एक के पास अचानक एक मुद्दा है, जहां वे आंशिक रूप से अमान्य JSON के माध्यम से भेजते हैं, जिससे आप NULL के रूप में एक सरणी को अलग कर सकते हैं: कोड, सबसे खराब रूप से, एक पूर्ण संदर्भ अपवाद को फेंक दिया, जिस पल पहला बुरा अनुरोध आया था, जिसे आप लॉगिंग में देखेंगे और फिर तुरंत क्लाइंट को उनके टूटे हुए अनुरोधों को ठीक करने के लिए कहेंगे, या आपका कोड कहता है "ओह, सरणी खाली है, कुछ भी नहीं करने के लिए!" और चुपचाप कुछ हफ्तों के लिए डीबी को 'खरीद टोकरी कोई आइटम नहीं था' लिखा?
GoatInTheMachine

10

यदि बार-बार अशक्त-चेक आपको परेशान करते हैं, तो आप अपने स्वयं के 'IsNullOrEmpty ()' विस्तार विधि बना सकते हैं, उस नाम से स्ट्रिंग विधि को मिरर करने के लिए, और null-check और .Any () दोनों कॉल को एक कॉल में लपेट सकते हैं।

अन्यथा, आपके प्रश्न के तहत एक टिप्पणी में @ 17 के 26 द्वारा उल्लिखित समाधान, 'मानक' विधि की तुलना में कम है, और नए अशक्त-सिंटैक्स से परिचित किसी व्यक्ति के लिए यथोचित रूप से स्पष्ट है।

if(myCollection?.Any() == true)

4
तुम भी इस्तेमाल कर सकते हैं ?? falseके बजाय == true। यह मुझे और अधिक स्पष्ट (क्लीनर) लगता है क्योंकि यह केवल के मामले को संभालता है null, और यह वास्तव में कोई और क्रिया नहीं है। ==बूलियंस के लिए प्लस चेक आमतौर पर मेरे गैग रिफ्लेक्स को ट्रिगर करते हैं। =)
jpmc26

2
@ jpmc26: मुझे C # के बारे में ज्यादा जानकारी नहीं है। क्यों myCollection?.Any()पर्याप्त नहीं है?
एरिक डुमिनील

6
@EricDuminil जिस तरह से नल-सशर्त ऑपरेटर काम करता है, उसके कारण, myCollection?.Any()प्रभावी रूप से एक साधारण बूलियन (अर्थात, बूल के बजाय बूल) के बजाय एक अशक्त- बूलियन को वापस कर देता है। बूल से कोई निहित रूपांतरण नहीं है? बूल के लिए, और यह एक बूल है जिसे हमें इस विशेष उदाहरण में ( ifस्थिति के भाग के रूप में परीक्षण करने के लिए ) की आवश्यकता है। इसलिए, हमें या तो trueशून्य-संचालक ऑपरेटर (??) के साथ स्पष्ट रूप से तुलना करनी चाहिए या उसका उपयोग करना चाहिए ।
स्टीवन रैंड

@ jpmc26 ?? असत्य पढ़ना कठिन है, फिर मायकल्शन? आपके गैग रिफ्लेक्स के बावजूद, == सच वही है जो आप अंतर्निहित परीक्षण की कोशिश कर रहे हैं। ?? झूठा सिर्फ अतिरिक्त शोर जोड़ता है और आपको अभी भी अपने सिर में मूल्यांकन करने की ज़रूरत है कि क्या होता है अगर अशक्त, यह अशक्त == विफल हो जाएगा, लगभग पाठक के बिना भी जागरूक होने के बिना ?.
रयान द लीच

2
@RyanTheLeach मुझे इस बारे में ज़्यादा सोचना ==होगा कि क्या वास्तव में काम करेगा। मैं पहले से ही जानता हूं कि एक बूलियन के साथ सहज रूप से क्या होता है जब यह केवल trueया हो सकता है false; मुझे इसके बारे में सोचना भी नहीं चाहिए। लेकिन nullमिश्रण में फेंक दो , और अब मुझे काम करना है कि क्या ==यह सही है। ??इसके बजाय केवल nullमामले को समाप्त करता है, इसे वापस कम करता है trueऔर false, जिसे आप पहले से ही तुरंत समझते हैं। मेरे गैग रिफ्लेक्स के लिए, जब मैं पहली बार इसे देखता हूं, तो मेरी तत्काल वृत्ति को बस इसे हटा देना है क्योंकि यह आमतौर पर बेकार है, जो आप नहीं चाहते हैं।
jpmc26

8

क्या मैं गलत हूँ, इस कोड के ग्राहक के रूप में, यह उम्मीद करने के लिए कि उदा ((int []) null)। किसी भी () को गलत नहीं लौटना चाहिए?

यदि आप उम्मीदों के बारे में सोचते हैं तो आपको इरादों के बारे में सोचना होगा।

null कुछ बहुत अलग से मतलब है Enumerable.Empty<T>

जैसा कि एरिक ईड्ट के उत्तर में उल्लेख किया गया है , के बीच अर्थ में अंतर है nullऔर एक खाली संग्रह है।

आइए पहले नज़र डालते हैं कि उनका उपयोग कैसे किया जाना चाहिए।

पुस्तक फ्रेमवर्क डिजाइन दिशानिर्देश: कन्वेंशन, मुहावरे, और पुन: प्रयोज्य .NET पुस्तकालयों के लिए पैटर्न, Microsoft आर्किटेक्ट्स द्वारा लिखित दूसरा संस्करण Krzysztof Cwalina और ब्रैड अब्राम निम्नलिखित सर्वोत्तम अभ्यास बताता है:

एक्स संग्रह गुणों से या वापस लौटने के तरीकों से शून्य मान वापस न करें। इसके बजाय एक खाली संग्रह या एक खाली सरणी लौटें।

अपने कॉलिंग के तरीके पर विचार करें जो अंततः डेटाबेस से डेटा प्राप्त कर रहा है: यदि आपको एक खाली सरणी प्राप्त होती है या Enumerable.Empty<T>इसका मतलब है कि आपका नमूना स्थान रिक्त है, अर्थात आपका परिणाम एक खाली सेट है । प्राप्त nullइस संदर्भ में, हालांकि, एक दर्शाता हैं त्रुटि राज्य

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


1
चाहे उनके अलग-अलग अर्थ हों वे संदर्भ पर अत्यधिक निर्भर हैं। अक्सर, जो भी तर्क हाथ में होता है, उसके उद्देश्य के लिए, वे समकक्ष अवधारणाओं का प्रतिनिधित्व करते हैं। हमेशा नहीं , लेकिन अक्सर।
jpmc26

1
@ jpmc26: मुझे लगता है कि इस उत्तर का मतलब यह है कि सी # के लिए दिशानिर्देशों को कोड करके उनका अलग अर्थ है। यदि आप चाहते हैं तो आप हमेशा सही कोड रख सकते हैं जहां रिक्त और रिक्त समान हैं। और कुछ मामलों में आप यह भी कर सकते हैं कि क्या यह शून्य या खाली है लेकिन इसका मतलब यह नहीं है कि उनका मतलब वही है।
क्रिस

@ क्रिस और मैं कह रहा हूं कि जिन लोगों ने भाषा डिज़ाइन की है, उनके कोडिंग दिशानिर्देशों का उपयोग आपकी आवश्यकताओं के संदर्भ में आपके कोड के मूल्यांकन के लिए प्रतिस्थापन के रूप में नहीं किया जा सकता है, आपके द्वारा उपयोग किए जा रहे पुस्तकालयों और आपके साथ अन्य डेवलपर्स। यह विचार कि वे संदर्भ में कभी भी समकक्ष नहीं होंगे, पाई-इन-द-स्काई आदर्शवाद है। वे सामान्य तौर पर हाथ में डेटा के लिए समान नहीं हो सकते हैं, लेकिन आपके द्वारा लिखे जा रहे कुछ विशिष्ट कार्यों में परिणाम उत्पन्न करने के लिए समान हो सकते हैं; उस स्थिति में, आपको दोनों का समर्थन करने की आवश्यकता है लेकिन यह सुनिश्चित करें कि वे एक ही परिणाम उत्पन्न करें।
jpmc26

आप जो कह रहे हैं उससे मैं भ्रमित हो सकता हूं लेकिन जब अशक्त और रिक्त एक परिणाम उत्पन्न करने के लिए बराबर होते हैं तो मैं यह नहीं देखता कि आप सिर्फ अलग का उपयोग क्यों नहीं करते हैं और एक बार दोनों को करने की एक विधि को चाहने के बजाय खाली चेक है। आपको उन्हें अन्य स्थितियों में अंतर करने की अनुमति नहीं देता है ...
क्रिस

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

3

ऐसे कई उत्तर हैं जो बताते हैं कि क्यों nullऔर खाली अलग-अलग हैं और पर्याप्त राय दोनों को समझाने की कोशिश कर रही है कि क्यों उन्हें अलग तरह से व्यवहार किया जाना चाहिए या नहीं। हालाँकि आप पूछ रहे हैं:

क्या मैं गलत हूँ, इस कोड के ग्राहक के रूप में, यह उम्मीद करने के लिए कि उदा ((int []) null)। किसी भी () को गलत नहीं लौटना चाहिए?

यह पूरी तरह से उचित उम्मीद है । आप के रूप में कर रहे हैं सही रूप में किसी और वर्तमान व्यवहार की वकालत। मैं वर्तमान कार्यान्वयन दर्शन से सहमत हूं लेकिन ड्राइविंग कारक केवल संदर्भ संदर्भों पर आधारित नहीं हैं।

यह देखते हुए कि Any()विधेय के बिना अनिवार्य रूप से है Count() > 0तो आप इस स्निपेट से क्या उम्मीद करते हैं?

List<int> list = null;
if (list.Count > 0) {}

या एक सामान्य:

List<int> list = null;
if (list.Foo()) {}

मुझे लगता है आप उम्मीद करते हैं NullReferenceException

  • Any()एक विस्तार विधि है, इसे सुचारू रूप से विस्तारित वस्तु के साथ एकीकृत किया जाना चाहिए फिर एक अपवाद फेंकना कम से कम आश्चर्यजनक बात है।
  • प्रत्येक .NET भाषा एक्सटेंशन के तरीकों का समर्थन नहीं करती है।
  • आप हमेशा कॉल कर सकते हैं Enumerable.Any(null)और वहां आप निश्चित रूप से उम्मीद करते हैं ArgumentNullException। यह एक ही विधि है और इसके अनुरूप होना चाहिए - संभवतः - फ्रेमवर्क में लगभग हर और।
  • nullऑब्जेक्ट तक पहुंचना एक प्रोग्रामिंग त्रुटि है , फ्रेमवर्क को जादू के मूल्य के रूप में अशक्त नहीं करना चाहिए । यदि आप इसे इस तरह से उपयोग करते हैं तो इससे निपटने की जिम्मेदारी आपकी है।
  • यह माना जाता है , आप एक तरह से सोचते हैं और मैं एक और तरीका सोचता हूं। फ्रेमवर्क जितना संभव हो उतना निर्विवाद होना चाहिए।
  • यदि आपके पास एक विशेष मामला है, तो आपको सुसंगत होना चाहिए : आपको सभी अन्य विस्तार विधियों के बारे में अधिक से अधिक उच्च विचार वाले निर्णय लेने होंगे: यदि Count()एक आसान निर्णय लगता है तो Where()नहीं है। किस बारे में Max()? यह एक EMPTY सूची के लिए एक अपवाद फेंकता है, क्या इसे एक के लिए भी नहीं फेंकना चाहिए null?

LINQ से पहले लाइब्रेरी डिज़ाइनरों ने क्या किया था जब nullएक वैध मूल्य (उदाहरण के लिए String.IsNullOrEmpty()) स्पष्ट तरीके पेश करना था, तो वे मौजूदा डिज़ाइन दर्शन के अनुरूप होना चाहिए । यह कहा, भले ही लिखने के लिए बहुत तुच्छ, दो तरीकों EmptyIfNull()और EmptyOrNull()आसान हो सकता है।


1

जिम को हर बैग में आलू छोड़ना चाहिए। नहीं तो मैं उसे मारने जा रहा हूं।

जिम में पांच आलू के साथ एक बैग है। क्या .Any()बैग में आलू हैं?

"हाँ," आप कहते हैं। <= सत्य

ठीक है तो जिम इस समय रहता है।

जिम सभी आलू को बाहर निकालता है और उन्हें खाता है। वहाँ हैं। किसी भी () बैग में आलू?

"नहीं," आप कहते हैं। <= झूठा

जिम को मारने का समय।

जिम बैग को पूरी तरह से आग में झोंक देता है। वहाँ हैं। अब () बैग में आलू?

"कोई बैग नहीं है।" <= तर्क-वितर्क अपवाद

जिम को जीना चाहिए या मरना चाहिए? वैसे हमें इसकी उम्मीद नहीं थी इसलिए मुझे सत्तारूढ़ होने की आवश्यकता है। जिम इस बग के साथ दूर हो रहा है या नहीं?

आप एनोटेशन का उपयोग यह संकेत देने के लिए कर सकते हैं कि आप इस तरह से किसी अशक्त शनीनागों के साथ नहीं हैं।

public bool Any( [NotNull] List bag ) 

लेकिन आपकी टूल चेन को इसका समर्थन करना होगा। जिसका अर्थ है कि आपके पास संभावना है कि आप अभी भी लेखन चेक समाप्त करेंगे।


0

यदि यह आपको इतना परेशान करता है, तो मैं एक सरल विस्तार विधि का सुझाव देता हूं।

static public IEnumerable<T> NullToEmpty<T>(this IEnumerable<T> source)
{
    return (source == null) ? Enumerable.Empty<T>() : source;
}

अब आप यह कर सकते हैं:

List<string> list = null;
var flag = list.NullToEmpty().Any( s => s == "Foo" );

... और झंडा लगाएगा false


2
returnकथन लिखने के लिए अधिक स्वाभाविक है :return source ?? Enumerable.Empty<T>();
जेपी स्टिग नीलसन

यह पूछे गए प्रश्न का उत्तर नहीं देता है।
केनेथ के।

@ केनेथ। लेकिन यह समस्या को हल करने के लिए लगता है।
RQDQ

0

यह C # के एक्सटेंशन विधियों और उनके डिज़ाइन दर्शन के बारे में एक प्रश्न है, इसलिए मुझे लगता है कि इस प्रश्न का उत्तर देने का सबसे अच्छा तरीका विस्तार विधियों के उद्देश्य पर MSDN के प्रलेखन को उद्धृत करना है :

एक्सटेंशन विधियाँ आपको नए व्युत्पन्न प्रकार बनाने, पुन: जमा करने, या अन्यथा मूल प्रकार को संशोधित किए बिना मौजूदा प्रकारों में "जोड़ने" के लिए सक्षम बनाती हैं। विस्तार विधियाँ एक विशेष प्रकार की स्थैतिक विधि होती हैं, लेकिन इन्हें वैसा ही कहा जाता है जैसे कि वे विस्तारित प्रकार पर उदाहरण के तरीके थे। C #, F # और विज़ुअल बेसिक में लिखे क्लाइंट कोड के लिए, एक एक्सटेंशन विधि और वास्तव में एक प्रकार से परिभाषित विधियों को कॉल करने के बीच कोई स्पष्ट अंतर नहीं है।

...

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

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

यदि आप किसी दिए गए प्रकार के विस्तार के तरीकों को लागू करते हैं, तो निम्न बिंदुओं को याद रखें:

  • एक विस्तार विधि को कभी भी नहीं कहा जाएगा यदि उसके प्रकार में परिभाषित विधि के समान हस्ताक्षर हैं।
  • एक्सटेंशन विधियों को नाम स्थान स्तर पर दायरे में लाया जाता है। उदाहरण के लिए, यदि आपके पास कई स्थिर वर्ग हैं जिनमें नामांकित एकल नाम स्थान में विस्तार विधियां हैं Extensions, तो वे सभी using Extensions;निर्देश द्वारा दायरे में लाए जाएंगे ।

संक्षेप में, एक्सटेंशन विधियों को एक विशेष प्रकार के उदाहरण के तरीकों को जोड़ने के लिए डिज़ाइन किया गया है, तब भी जब डेवलपर्स सीधे ऐसा नहीं कर सकते। और क्योंकि उदाहरण विधियाँ हमेशा एक्सटेंशन विधियों को ओवरराइड करेंगी यदि मौजूद हैं (यदि इंस्टेंस विधि सिंटैक्स का उपयोग करके कहा जाता है), तो यह केवल तभी किया जाना चाहिए जब आप सीधे एक विधि नहीं जोड़ सकते हैं या क्लास का विस्तार कर सकते हैं। *

दूसरे शब्दों में, एक विस्तार विधि को एक आवृत्ति विधि की तरह कार्य करना चाहिए, क्योंकि यह अंत में कुछ क्लाइंट द्वारा एक इंस्टेंस विधि बनाया जा सकता है। और क्योंकि एक इंस्टेंस मेथड को फेंकना चाहिए यदि ऑब्जेक्ट जिस पर कॉल किया जा रहा है null, वह है एक्सटेंशन विधि।


जब सी # 3.0 जारी किया गया था, वहाँ पहले से ही उपयोग कर रहे थे कि ग्राहकों के लाखों लोगों थे: * एक तरफ ध्यान दें के रूप में, यह वास्तव में स्थिति यह है कि LINQ के डिजाइनरों का सामना करना पड़ा है System.Collections.IEnumerableऔर System.Collections.Generic.IEnumerable<T>अपने संग्रह में और दोनों में, foreachछोरों। इन कक्षाओं लौटे IEnumeratorजिन वस्तुओं पर केवल दो तरीकों था Currentऔर MoveNextहै, इसलिए इस तरह के रूप में किसी भी अतिरिक्त आवश्यकता उदाहरण के तरीकों, जोड़ने Count, Anyआदि, ग्राहकों के इन लाखों लोगों को तोड़ने की जाएगी। इसलिए, यह कार्यक्षमता प्रदान करने के लिए (विशेषकर जब से इसे Currentऔर MoveNextरिश्तेदार आसानी से लागू किया जा सकता है), उन्होंने इसे विस्तार विधियों के रूप में जारी किया, जिसे वर्तमान में किसी भी लागू किया जा सकता है।IEnumerableउदाहरण और अधिक कुशल तरीकों से कक्षाओं द्वारा भी लागू किया जा सकता है। अगर C # के डिजाइनरों ने पहले दिन LINQ जारी करने का निर्णय लिया होता, तो यह उदाहरण के तरीकों के रूप में प्रदान किया गया होता IEnumerable, और संभवत: उन्होंने उन तरीकों के डिफ़ॉल्ट इंटरफ़ेस कार्यान्वयन प्रदान करने के लिए किसी प्रकार की प्रणाली को डिज़ाइन किया होता।


0

मुझे लगता है कि यहाँ मुख्य बिंदु यह है कि अपवाद को फेंकने के बजाय झूठी वापसी करके, आप ऐसी सूचनाओं को बाधित कर रहे हैं जो भविष्य के पाठकों / आपके कोड के संशोधक के लिए प्रासंगिक हो सकती हैं।

यदि यह सूची के अशक्त होने के लिए संभव है, तो मैं सुझाव दूंगा कि उसके लिए एक अलग तर्क मार्ग हो, अन्यथा भविष्य में कोई व्यक्ति आपके आधार के {}} में कुछ सूची आधारित तर्क (जैसे एक जोड़) जोड़ सकता है, जिसके परिणामस्वरूप अवांछित अपवाद है कि उनके पास भविष्यवाणी करने का कोई कारण नहीं था।

पठनीयता और स्थिरता ट्रम्प 'हर बार मुझे एक अतिरिक्त शर्त' लिखनी पड़ती है।


0

एक सामान्य नियम के रूप में, मैं अपने अधिकांश कोड को यह मानने के लिए लिखता हूं कि कॉलर मुझे अशक्त डेटा न सौंपने के लिए जिम्मेदार है, ज्यादातर यह कहता है कि No No to Null (और अन्य समान पोस्ट) में उल्लिखित कारणों के लिए । नल की अवधारणा को अक्सर अच्छी तरह से नहीं समझा जाता है, और इस कारण से, यह आपके चर को समय से पहले शुरू करने की सलाह दी जाती है, जितना कि व्यावहारिक। यह मानते हुए कि आप एक उचित एपीआई के साथ काम कर रहे हैं, आपको आदर्श रूप से कभी भी अशक्त मूल्य वापस नहीं लेना चाहिए, इसलिए आपको कभी भी अशक्त होने की जांच नहीं करनी चाहिए। अशक्त की बात, जैसा कि अन्य उत्तरों में कहा गया है, यह सुनिश्चित करने के लिए है कि आपके पास वैध वस्तु (जैसे "बैग") जारी रखने से पहले काम करना है। यह एक विशेषता नहीं है Any, बल्कि भाषा की एक विशेषता हैअपने आप। आप एक अशक्त वस्तु पर अधिकांश ऑपरेशन नहीं कर सकते, क्योंकि यह मौजूद नहीं है। यह ऐसा है जैसे अगर मैं आपसे अपनी कार में स्टोर करने के लिए कहूं, तो मेरे पास कार नहीं है, इसलिए आपके पास स्टोर पर ड्राइव करने के लिए मेरी कार का उपयोग करने का कोई तरीका नहीं है। किसी ऐसी चीज़ पर ऑपरेशन करना निरर्थक है जिसका शाब्दिक अर्थ नहीं है।

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

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