फ़ॉरच लूप में नल की जाँच करें


97

वहाँ निम्नलिखित करने का एक अच्छा तरीका है:
मैं फ़ाइल पर होने के लिए अशक्त के लिए एक जाँच की जरूरत है। लूप के साथ आगे बढ़ने से पहले।

if (file.Headers != null)
{
  foreach (var h in file.Headers)
  {
   //set lots of properties & some other stuff
  }
}

संक्षेप में, अगर यह मेरे कोड में हो रहे इंडेंटेशन के स्तर के कारण फॉर्च के अंदर लिखने के लिए थोड़ा बदसूरत लगता है।

कुछ ऐसा है जिसका मूल्यांकन किया जाएगा

foreach(var h in (file.Headers != null))
{
  //do stuff
}

मुमकिन?


3
आप यहाँ एक नज़र रख सकते हैं: stackoverflow.com/questions/6937407/…
एड्रियन फ़ासिउ जूल

stackoverflow.com/questions/872323/… एक और विचार है।
Weismat

1
@ AdrianFaciu मुझे लगता है कि यह पूरी तरह से अलग है। प्रश्न यह जाँचता है कि क्या संग्रह प्रत्येक के लिए करने से पहले सबसे पहले शून्य है। आपका लिंक यह जाँचता है कि संग्रह में मौजूद वस्तु अशक्त है या नहीं।
रीतिकिटिक


1
C # 8 में किसी प्रकार की अशक्त स्थिति हो सकती है, जैसे कि वाक्य रचना: foreach? {
एमएमएस

जवाबों:


124

रूण के सुझाव के लिए एक मामूली कॉस्मेटिक अतिरिक्त के रूप में, आप अपनी खुद की एक्सटेंशन विधि बना सकते हैं:

public static IEnumerable<T> OrEmptyIfNull<T>(this IEnumerable<T> source)
{
    return source ?? Enumerable.Empty<T>();
}

तो आप लिख सकते हैं:

foreach (var header in file.Headers.OrEmptyIfNull())
{
}

स्वाद के अनुसार नाम बदलें :)


80

यह मानते हुए कि फ़ाइल में तत्वों के प्रकार। Headers T है आप ऐसा कर सकते हैं

foreach(var header in file.Headers ?? Enumerable.Empty<T>()){
  //do stuff
}

यदि फ़ाइल रिक्त हो तो यह टी का एक खाली स्थान बना देगा। यदि फ़ाइल का प्रकार एक प्रकार है जिसका आप स्वयं स्वामी हैं, हालाँकि, Headersइसके बदले गेटर बदलने पर विचार करें । nullअज्ञात का मान है इसलिए यदि संभव हो तो अशक्त के रूप में उपयोग करने के बजाय "मुझे पता है कि कोई तत्व नहीं हैं" जब अशक्त वास्तव में (/ मूल रूप से) की व्याख्या की जानी चाहिए "मुझे नहीं पता कि क्या कोई तत्व हैं" दिखाने के लिए एक खाली सेट का उपयोग करें कि आप जानते हैं कि सेट में कोई तत्व नहीं हैं। यह भी DRY'er होगा क्योंकि आपको नल की जांच अक्सर नहीं करनी होगी।

संपादित एक के रूप में Jons सुझाव पर अनुवर्ती कार्रवाई, आप भी एक विस्तार विधि के लिए ऊपर दिए गए कोड को बदलने बना सकते हैं

foreach(var header in file.Headers.OrEmptyIfNull()){
  //do stuff
}

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

ऊपर उल्लिखित विस्तार विधि ऑप्टिमाइज़र का पता लगाने के लिए कुछ अनुकूलन को असंभव बना सकती है। विशेष रूप से, जो इस पद्धति को ओवरलोडिंग का उपयोग करके IList से संबंधित हैं, उन्हें समाप्त किया जा सकता है

public static IList<T> OrEmptyIfNull<T>(this IList<T> source)
{
    return source ?? Array.Empty<T>();
}

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

@ एक तरफ से एक नल की जाँच करें उन मामलों के लिए कोई जुर्माना नहीं है जहां प्रगणक शून्य नहीं है। उस जाँच से बचना, जबकि यह सुनिश्चित करना कि गणना योग्य नहीं है, असंभव है। ऊपर दिए गए कोड के लिए हेडर की आवश्यकता होती है, IEnumerable जो foreachआवश्यकताओं से अधिक प्रतिबंधात्मक है, लेकिन List<T>आपके द्वारा लिंक किए गए उत्तर में आवश्यकता से कम प्रतिबंधात्मक है । जो परीक्षण के एक ही प्रदर्शन का दंड है कि क्या गणना योग्य है या नहीं।
एफएस

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

@tom उत्तर का आधार यह है कि फ़ाइल.हेडर्स एक IEnumerable <T> है जिसमें कंपाइलर ऑप्टिमाइज़ेशन नहीं कर सकता है। हालांकि इससे बचने के लिए विस्तार विधि समाधान का विस्तार करना सीधे तौर पर आसान है। संपादित देखें
Rune FS

19

सच कहूँ तो, मैं सलाह देता हूँ: बस nullटेस्ट को चूसो । एक nullपरीक्षण सिर्फ एक brfalseया है brfalse.s; सब कुछ बहुत अधिक काम (परीक्षण, कार्य, अतिरिक्त विधि कॉल, अनावश्यक शामिल हो रहा है GetEnumerator(), MoveNext(), Dispose()पुनरावर्तक पर, आदि)।

एक ifपरीक्षण सरल, स्पष्ट और कुशल है।


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

3
इस मार्क पर बस एक त्वरित टिप्पणी .. मैंने यह सवाल पूछा और कुछ प्रदर्शन संवर्द्धन को लागू करने की आवश्यकता के बाद, आपकी सलाह बेहद काम आई। धन्यवाद
एमिनेम

13

"अगर" चलना ठीक होने से पहले है, तो उनमें से कुछ "सुंदर" शब्दार्थ आपके कोड को कम पठनीय बना सकते हैं।

वैसे भी, अगर इंडेंटेशन परेशान करता है, तो आप चेक करने के लिए बदल सकते हैं:

if(file.Headers == null)  
   return;

और आप हेडर प्रॉपर्टी पर सही मूल्य होने पर ही फॉरच लूप को प्राप्त करेंगे।

एक और विकल्प जो मैं सोच सकता हूं कि आपके फ़ॉरेस्ट लूप के अंदर नल-कोलेसिंग ऑपरेटर का उपयोग कर रहा है और पूरी तरह से शून्य जाँच से बचने के लिए। नमूना:

List<int> collection = new List<int>();
collection = null;
foreach (var i in collection ?? Enumerable.Empty<int>())
{
    //your code here
}

(संग्रह को अपनी वास्तविक वस्तु / प्रकार से बदलें)


यदि आपके स्टेटमेंट के बाहर कोई कोड है तो आपका पहला विकल्प काम नहीं करेगा।
रीतिकिटिक

मैं मानता हूं, अगर नई सूची बनाने की तुलना में लागू करना आसान और सस्ता है, तो कोड सौंदर्यीकरण के लिए।
एंड्रियास जोहानसन

10

Null- सशर्त ऑपरेटर और ForEach () का उपयोग करना जो मानक foreach लूप की तुलना में तेज़ी से काम करता है।
आपको हालांकि संग्रह को सूची में डालना होगा।

   listOfItems?.ForEach(item => // ... );

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

मेरे मामले के लिए सबसे अच्छा समाधान
जोसेफ हेने

3

मैं इन परिदृश्यों के लिए एक अच्छा सा विस्तार विधि का उपयोग कर रहा हूं:

  public static class Extensions
  {
    public static IList<T> EnsureNotNull<T>(this IList<T> list)
    {
      return list ?? new List<T>();
    }
  }

यह देखते हुए कि हेडर्स टाइप सूची के हैं, आप निम्न कार्य कर सकते हैं:

foreach(var h in (file.Headers.EnsureNotNull()))
{
  //do stuff
}

1
आप ??ऑपरेटर का उपयोग कर सकते हैं और रिटर्न स्टेटमेंट को छोटा कर सकते हैंreturn list ?? new List<T>;
FS

1
@wolfgangziegler, अगर मैं सही ढंग से समझता हूं कि nullआपके नमूने में परीक्षण की file.Headers.EnsureNotNull() != nullआवश्यकता नहीं है, और क्या यह गलत है?
रेम्को जानसेन

0

कुछ मामलों के लिए, मैं थोड़ा और अधिक पसंद करूँगा, सामान्य संस्करण, यह मानते हुए कि एक नियम के रूप में, डिफ़ॉल्ट संग्रह निर्माता खाली उदाहरण लौटाते हैं।

इस विधि को नाम देना बेहतर होगा NewIfDefault। यह न केवल संग्रह के लिए उपयोगी हो सकता है, इसलिए प्रकार की बाधा IEnumerable<T>शायद बेमानी है।

public static TCollection EmptyIfDefault<TCollection, T>(this TCollection collection)
        where TCollection: class, IEnumerable<T>, new()
    {
        return collection ?? new TCollection();
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.