क्या है (आइटम! = Null) फ़र्क़ से पहले ही फ़ालतू (आइटमों में T आइटम)?


104

मैं अक्सर निम्नलिखित की तरह कोड भर में आता हूं:

if ( items != null)
{
   foreach(T item in items)
   {
        //...
   }
}

मूल रूप से, ifस्थिति यह सुनिश्चित करती है कि foreachब्लॉक केवल तभी निष्पादित होगा जब itemsशून्य नहीं है। मैं सोच रहा था कि क्या ifहालत वास्तव में जरूरत है, या foreachअगर मामला संभाल लेंगे items == null

मेरा मतलब है, क्या मैं बस लिख सकता हूं

foreach(T item in items)
{
    //...
}

इस बारे में चिंता किए बिना कि क्या itemsअशक्त है या नहीं? क्या ifहालत बेहाल है? या इस पर निर्भर करता है प्रकार की itemsशायद पर या Tके रूप में अच्छी तरह से?



1
@ kjbartel का जवाब (" stackoverflow.com/a/32134295/401246 पर" सबसे अच्छा समाधान है, क्योंकि यह नहीं है :) a) प्रदर्शन में गिरावट को शामिल करता है (भले ही नहीं null) एलसीडी के लिए पूरे लूप को सामान्य करना Enumerable(जैसा कि उपयोग ??करना होगा) ), बी) को हर प्रोजेक्ट में एक एक्सटेंशन मेथड जोड़ने की आवश्यकता है, या c) null IEnumerableएस से बचने की आवश्यकता है (Pftft! Puh-LEAZE! SMH।) के साथ शुरू करने के लिए (cuz, nullN / A का मतलब है, जबकि खाली सूची का मतलब है, यह appl है। लेकिन वर्तमान में, अच्छी तरह से, खाली ; यानी, एक एंपल कमीशन हो सकता है कि गैर-बिक्री के लिए एन / ए है या बिक्री के लिए खाली है जब उन्होंने कोई कमाई नहीं की है)।
टॉम

जवाबों:


115

आपको अभी भी यह जांचने की आवश्यकता है कि क्या (आइटम! Null) अन्यथा आपको NullReferenceException मिल जाएगी। हालाँकि आप ऐसा कुछ कर सकते हैं:

List<string> items = null;  
foreach (var item in items ?? new List<string>())
{
    item.Dump();
}

लेकिन आप इसके प्रदर्शन की जांच कर सकते हैं। इसलिए मैं अभी भी अगर (आइटम! = अशक्त) पहले पसंद कर रहा हूँ।

एरिक के लिपिपर्ट सुझाव के आधार पर मैंने कोड को इसमें बदल दिया:

List<string> items = null;  
foreach (var item in items ?? Enumerable.Empty<string>())
{
    item.Dump();
}

31
प्यारा विचार; एक खाली सरणी बेहतर होगी क्योंकि यह कम मेमोरी का उपभोग करती है और कम मेमोरी का दबाव पैदा करती है। Enumerable.Empty <string> यह और भी बेहतर होगा क्योंकि यह खाली सरणी को उत्पन्न करता है और इसे फिर से उपयोग करता है।
एरिक लिपर्ट

5
मुझे उम्मीद है कि दूसरा कोड धीमा होगा। यह क्रम को IEnumerable<T>अधोगामी बना देता है जो एक इंटरफ़ेस को प्रगणक बनाने के लिए गणना करने के लिए अपमानित करता है। मेरे परीक्षण में एक इंट सरणी पर पुनरावृत्ति के लिए एक कारक 5 गिरावट देखी गई।
कोडइन्चोस

11
@CodeInChaos: क्या आप आमतौर पर पाते हैं कि खाली क्रम को मानने की गति आपके कार्यक्रम में प्रदर्शन की अड़चन है?
एरिक लिपर्ट

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

15
@CodeInChaos: आह, मैं अब आपकी बात देख रहा हूं। जब कंपाइलर यह पता लगा सकता है कि "फॉर्च्यूनर" एक सूची <टी> या एक सरणी से अधिक चल रहा है तो यह मूल्य-प्रकार के एन्यूमरेटर्स का उपयोग करने के लिए फॉर्च को अनुकूलित कर सकता है या वास्तव में "लूप" के लिए उत्पन्न कर सकता है। जब किसी सूची या खाली अनुक्रम को समझने के लिए मजबूर किया जाता है, तो उसे "सबसे सामान्य सामान्य भाजक" कोडजेन पर वापस जाना पड़ता है, जो कुछ मामलों में धीमा हो सकता है और अधिक मेमोरी दबाव पैदा कर सकता है। यह एक सूक्ष्म लेकिन उत्कृष्ट बिंदु है। बेशक, कहानी का नैतिक है - हमेशा की तरह - यदि आपको एक पूर्ण समस्या है, तो यह पता लगाने के लिए प्रोफ़ाइल करें कि असली अड़चन क्या है।
एरिक लिपर्ट

69

C # 6 का उपयोग करके आप नए null सशर्त ऑपरेटर को एक साथ List<T>.ForEach(Action<T>)(या अपनी खुद की IEnumerable<T>.ForEachएक्सटेंशन विधि) उपयोग कर सकते हैं ।

List<string> items = null;
items?.ForEach(item =>
{
    // ...
});

सुरुचिपूर्ण उत्तर। धन्यवाद!
स्टीव

2
यह सबसे अच्छा समाधान है, क्योंकि यह नहीं है: ए) के प्रदर्शन में गिरावट शामिल है (तब भी जब नहीं null) एलसीडी को पूरे लूप को सामान्य करना Enumerable(जैसे कि उपयोग ??करना), बी) को प्रत्येक परियोजना में एक्सटेंशन विधि जोड़ने की आवश्यकता होती है, या सी ) से बचने की आवश्यकता है null IEnumerable(Pftft! Puh-LEAZE! SMH।) के साथ शुरू करने के लिए (cuz, nullजिसका अर्थ है N / A, जबकि खाली सूची का मतलब है, यह appl है। लेकिन वर्तमान में, ठीक है, खाली है !), यानी एक Empl कमीशन हो सकता है। गैर-बिक्री के लिए एन / ए या बिक्री के लिए खाली जब उन्होंने कोई कमाई नहीं की है)।
टॉम

6
@ टोम: यह मानता है कि itemsएक List<T>है, बल्कि किसी भी तरह से IEnumerable<T>। (या आपके पास एक कस्टम एक्सटेंशन विधि है, जो आपने कहा है कि आप वहां नहीं होना चाहते ...) इसके अलावा, मैं कहूंगा कि यह वास्तव में 11 टिप्पणियों को जोड़ने के लायक नहीं है सभी मूल रूप से कह रहे हैं कि आपको एक विशेष उत्तर पसंद है।
जॉन स्कीट

2
@ टॉम: मैं भविष्य में ऐसा करने से आपको हतोत्साहित करूंगा। सोचिए अगर आपकी टिप्पणी से असहमत हर कोई अपनी टिप्पणी को आप सभी के साथ जोड़े । (कल्पना करें कि मैंने अपना उत्तर यहाँ पर 11 बार लिखा।) यह केवल स्टैक ओवरफ्लो का उत्पादक उपयोग नहीं है।
जॉन स्कीट

1
मुझे यह भी लगता है कि प्रतिनिधि को एक मानक के रूप में पुकारते हुए एक प्रदर्शन होगा foreach। विशेष रूप से एक सूची के लिए जो मुझे लगता है कि forलूप में परिवर्तित हो जाता है ।
kjbartel

37

यहाँ वास्तविक takeaway एक अनुक्रम होना चाहिए पहली जगह में लगभग कभी भी अशक्त नहीं होना चाहिए । बस अपने सभी कार्यक्रमों में इसे एक ऐसा बदलाव बनाएं कि यदि आपके पास एक अनुक्रम है, तो यह कभी भी अशक्त नहीं है। यह हमेशा खाली अनुक्रम या कुछ अन्य वास्तविक अनुक्रम होने के लिए आरंभिक होता है।

यदि कोई अनुक्रम कभी अशक्त नहीं है, तो जाहिर है कि आपको इसकी जांच करने की आवश्यकता नहीं है।


2
कैसे के बारे में अगर आप एक WCF सेवा से अनुक्रम मिलता है? यह अशक्त हो सकता है, है ना?
नवाज

4
@ नवाज़: अगर मेरे पास एक WCF सेवा होती जो मुझे अशक्त अनुक्रम लौटा देती, जो उन्हें खाली क्रम बनाने के लिए प्रेरित करती, तो मैं उन्हें बग के रूप में रिपोर्ट करता। उस ने कहा: यदि आपको यकीनन छोटी गाड़ी सेवाओं के बुरी तरह से निर्मित आउटपुट से निपटना है, तो हां, आपको अशक्त की जांच करके इससे निपटना होगा।
एरिक लिपर्ट

7
जब तक, ज़ाहिर है, अशक्त और खाली का मतलब पूरी तरह से अलग चीजें हैं। कभी-कभी यह अनुक्रमों के लिए मान्य होता है।
विन्यासकर्ता

@ नवाज़ कैसे DataTable.Rows के बारे में है कि एक खाली संग्रह के बजाय अशक्त देता है। शायद यह एक बग है?
नील बी

@ kjbartel का जवाब (" stackoverflow.com/a/32134295/401246 पर" सबसे अच्छा समाधान है, क्योंकि यह नहीं है :) a) प्रदर्शन में गिरावट को शामिल करता है (भले ही नहीं null) एलसीडी के लिए पूरे लूप को सामान्य करना Enumerable(जैसा कि उपयोग ??करना होगा) ), बी) को हर प्रोजेक्ट में एक एक्सटेंशन मेथड जोड़ने की आवश्यकता है, या c) null IEnumerableएस से बचने की आवश्यकता है (Pftft! Puh-LEAZE! SMH।) के साथ शुरू करने के लिए (cuz, nullN / A का मतलब है, जबकि खाली सूची का मतलब है, यह appl है। लेकिन वर्तमान में, अच्छी तरह से, खाली ; यानी, एक एंपल कमीशन हो सकता है कि गैर-बिक्री के लिए एन / ए है या बिक्री के लिए खाली है जब उन्होंने कोई कमाई नहीं की है)।
टॉम

10

वास्तव में उस पर एक सुविधा का अनुरोध है @Connect: http://connect.microsoft.com/VisualStudio/feedback/details/93497/foreach-should-check-for-null

और प्रतिक्रिया काफी तार्किक है:

मुझे लगता है कि अधिकांश फॉरेस्ट लूप एक गैर-अशक्त संग्रह को पुनरावृत्त करने के इरादे से लिखे गए हैं। यदि आप अशक्त के माध्यम से पुनरावृत्ति करने की कोशिश करते हैं, तो आपको अपना अपवाद प्राप्त करना चाहिए, ताकि आप अपना कोड ठीक कर सकें।


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

6

आप इसे हमेशा एक अशक्त सूची के साथ देख सकते हैं ... लेकिन यह वही है जो मैंने msdn वेबसाइट पर पाया है

foreach-statement:
    foreach   (   type   identifier   in   expression   )   embedded-statement 

यदि अभिव्यक्ति में मान शून्य है, तो System.NullReferenceException को फेंक दिया जाता है।


2

यह अतिश्योक्ति नहीं है। रनटाइम आइटम्स को एक IEnumerable में डाला जाएगा और इसके GetEnumerator मेथड को बुलाया जाएगा। यह उन आइटमों की एक dereferencing का कारण होगा जो विफल हो जाएंगे


1
1) अनुक्रम जरूरी नहीं होगा IEnumerableऔर 2) यह फेंकने के लिए एक डिजाइन निर्णय है। nullयदि डेवलपर्स अच्छी तरह से विचार करते हैं तो C # उस चेक को आसानी से सम्मिलित कर सकता है।
कोडइंचोस

2

आप एक विस्तार विधि में अशक्त जांच को रोक सकते हैं और एक लैम्ब्डा का उपयोग कर सकते हैं:

public static class EnumerableExtensions {
  public static void ForEach<T>(this IEnumerable<T> self, Action<T> action) {
    if (self != null) {
      foreach (var element in self) {
        action(element);
      }
    }
  }
}

कोड बन जाता है:

items.ForEach(item => { 
  ...
});

यदि आप और अधिक संक्षिप्त हो सकते हैं यदि आप केवल एक विधि को कॉल करना चाहते हैं जो एक आइटम लेता है और रिटर्न करता है void:

items.ForEach(MethodThatTakesAnItem);

1

आपको इसकी जरूरत है। foreachकंटेनर को एक्सेस करने के लिए अन्यथा एक्सेस करने पर आपको एक अपवाद मिलेगा ।

कवर के तहत, पुनरावृत्ति करने के लिए संग्रह वर्ग पर लागू इंटरफ़ेसforeach का उपयोग करता है । सामान्य समकक्ष इंटरफ़ेस यहाँ है

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


1
बस एक नोट के रूप में यह तकनीकी रूप से इंटरफ़ेस का उपयोग नहीं करता है, यह बतख टाइपिंग का उपयोग करता है: blogs.msdn.com/b/kcwalina/archive/2007/07/18/ducknotation.aspx इंटरफेस यह सुनिश्चित करते हैं कि सही तरीके और गुण हैं। हालांकि, और सहायता आशय की समझ। साथ ही साथ बाहर की
आड़ू का

0

परीक्षण आवश्यक है, क्योंकि यदि संग्रह शून्य है, तो फ़ॉरच्यूनल NullReferenceException को फेंक देगा। यह वास्तव में इसे आज़माने के लिए काफी सरल है।

List<string> items = null;
foreach(var item in items)
{
   Console.WriteLine(item);
}

0

दूसरा NullReferenceExceptionसंदेश के साथ फेंक देगाObject reference not set to an instance of an object.


0

जैसा कि यहां बताया गया है कि आपको जांचने की आवश्यकता है कि क्या यह अशक्त नहीं है।

एक अभिव्यक्ति का उपयोग न करें जो अशक्त करने के लिए मूल्यांकन करता है।


0

C # 6 में आप इस तरह से sth लिख सकते हैं:

// some string from file or UI, i.e.:
// a) string s = "Hello, World!";
// b) string s = "";
// ...
var items = s?.Split(new char[] { ',', '!', ' ' }) ?? Enumerable.Empty<string>();  
foreach (var item in items)
{
    //..
}

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

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