क्या C # में "खाली सूची" सिंगलटन है?


80

C # में मैं LINQ और IEnumerable का एक अच्छा सा उपयोग करता हूं। और सब अच्छी तरह से और अच्छा है (या कम से कम ज्यादातर तो)।

हालांकि, कई मामलों में मैं खुद को पाता हूं कि मुझे IEnumerable<X>एक डिफ़ॉल्ट के रूप में एक खाली की आवश्यकता है । यही है, मैं चाहूंगा

for (var x in xs) { ... }

बिना जांच-पड़ताल के काम करना। अब यह वही है जो मैं वर्तमान में करता हूं, जो बड़े संदर्भ पर निर्भर करता है:

var xs = f() ?? new X[0];              // when xs is assigned, sometimes
for (var x in xs ?? new X[0]) { ... }  // inline, sometimes

अब, जबकि उपरोक्त मेरे लिए पूरी तरह से ठीक है - अर्थात, यदि कोई ऑब्जेक्ट "अतिरिक्त ओवरहेड" है, तो सरणी ऑब्जेक्ट बनाने के साथ मैं बस परवाह नहीं करता - मैं सोच रहा था:

क्या C # /। NET में "खाली अपरिवर्तनीय IEnumerable / IList" सिंगलटन है? (और, भले ही नहीं, क्या ऊपर वर्णित मामले को संभालने का एक "बेहतर" तरीका है?)

जावा के पास Collections.EMPTY_LISTअपरिवर्तनीय सिंगलटन है - "अच्छी तरह से टाइप किया हुआ" Collections.emptyList<T>()- जो इस उद्देश्य को पूरा करता है, हालांकि मुझे यकीन नहीं है कि अगर एक समान अवधारणा सी # में भी काम कर सकती है क्योंकि जेनरिक को अलग तरीके से संभाला जाता है।

धन्यवाद।


खैर, रफ़ू :) यह वही है जो मुझे सूची / IList पर ध्यान केंद्रित करने के लिए मिलता है और न कि Enumerable / IEnumerable के लिए, सभी धन्यवाद - चारों ओर वोट।


2
public static class Array<T> { public static readonly T[] Empty = new T[0]; }और इसे इस तरह कहा जा सकता है Array<string>.Empty:। मैंने इसके बारे में यहाँ CodeReview में पूछा
फाक गूर

जवाबों:


98

आप ढूंढ रहे हैं Enumerable.Empty<T>()

अन्य समाचारों में जावा खाली सूची बेकार हो जाती है क्योंकि सूची इंटरफ़ेस तत्वों को सूची में जोड़ने के तरीकों को उजागर करता है जो अपवादों को फेंकते हैं।


यह एक बहुत ही मान्य बिंदु है! शायद यह एक नया SO प्रश्न वारंट करता है?

1
आप कुछ सेकंड धीमे थे और कोई डॉक्यूमेंट लिंक * फिंगर शेक * ;-) नहीं है, लेकिन svicks कमेंट पर विस्तार के लिए स्वीकार करें।

इसके अलावा अन्य लोगों को अधिक अपवित्र मिला, इसलिए हम भी :) मैं एक प्रश्न पोस्ट करूंगा लेकिन मैं अभी बिस्तर पर जा रहा हूं और मैं इस प्रश्न का पालन नहीं कर पाऊंगा। इसे स्वयं क्यों न पोस्ट करें?
स्टिलगर

32
क्योंकि एक वर्ग विधि को एक List(एक संग्रह जो सूचकांक द्वारा पहुँचा जा सकता है) को वापस करने की आवश्यकता हो सकती है। जिन्हें Listआसानी से पढ़ा जा सकता है। और कभी-कभी आपको Listइसमें शून्य तत्व के साथ इतनी आसानी से वापस लौटने की आवश्यकता होती है। इस प्रकार, Collections.emptyList()विधि। आप केवल एक खाली Iterable नहीं लौटा सकते क्योंकि एक कार्यान्वित इंटरफ़ेस निर्दिष्ट करता है कि विधि एक सूची लौटाती है। बड़ी समस्या यह है कि उनका कोई ImmutableList इंटरफ़ेस नहीं है जिसे आप वापस कर सकते हैं। .NET में भी यही समस्या है: कोई IListभी अच्छी तरह से पढ़ सकता है।
लॉरेंट बॉरगॉउल-रॉय

6
एक साइड नोट पर, प्रत्येक सरणी C # में एक IList <संगत टाइप> है, और जब आप नए आइटम को जोड़ने का प्रयास करेंगे तो यह फेंक देगा।
ग्रेजेनियो

52

Enumerable.Empty<T>() यह ठीक है।


3
खैर, बिल्कुल नहीं । :) चूंकि "सूची" के लिए कहा गया था, Array.Empty<T>()इसलिए अधिक सटीक है, क्योंकि यह एक है IList<T>। इसका संतोषजनक लाभ भी है IReadOnlyCollection<T>। बेशक, जहां एक की IEnumerable<T> करता है पर्याप्त, Enumerable.Empty<T>()बिल्कुल फिट बैठता है।
टिमो

3
@ इस सवाल पर, और इस एक सहित कई जवाब, लगभग 3 साल पहले Array.Empty<T>उपलब्ध कराए गए थे। :) किसी भी मामले में, शीर्षक के बावजूद, सवाल यह स्पष्ट रूप से स्पष्ट करता है कि IEnumerable<T>उद्देश्य के लिए अच्छा है।
जॉन

19

मुझे लगता है कि आप ढूंढ रहे हैं Enumerable.Empty<T>()

खाली सूची सिंगलटन का इतना अर्थ नहीं होता है, क्योंकि सूची अक्सर परिवर्तनशील होती है।


14

अपने मूल उदाहरण में आप एक खाली एरेनेरेबल का उपयोग करते हैं। जबकि का उपयोग कर Enumerable.Empty<T>()पूरी तरह से ठीक है, वहाँ अन्य मामलों हो सकता है: आप अगर उपयोग करने के लिए एक सरणी (या IList<T>इंटरफ़ेस), आप विधि का उपयोग कर सकते हैं

System.Array.Empty<T>()

जो आपको अनावश्यक आवंटन से बचने में मदद करता है।

नोट्स / संदर्भ:


यह इंगित करने के लिए धन्यवाद कि दस्तावेज़ रसेलिन विश्लेषक के साथ लाइन से बाहर है। क्या तुमने कभी सही करने के लिए GitHub पर एक मुद्दा खोला?
जॉन ज़ब्रोस्की

10

मुझे लगता है कि एक विस्तार विधि जोड़ने से नलियों को संभालने की उनकी क्षमता के लिए एक साफ विकल्प है - कुछ इस तरह:

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

  foreach(var x in xs.EmptyIfNull())
  {
    ...
  }

1

Microsoft ने इस तरह से (किसी भी) को लागू किया ( स्रोत )

public static bool Any<TSource>(this IEnumerable<TSource> source)
{
    if (source == null) throw new ArgumentNullException("source");
    using (IEnumerator<TSource> e = source.GetEnumerator())
    {
        if (e.MoveNext()) return true;
    }
    return false;
}

यदि आप कॉल स्टैक पर कॉल सहेजना चाहते हैं !Any(), तो कॉल करने वाली एक्सटेंशन विधि लिखने के बजाय , बस इन तीन परिवर्तनों को फिर से लिखें:

public static bool IsEmpty<TSource>(this IEnumerable<TSource> source) //first change (name)
{
    if (source == null) throw new ArgumentNullException("source");
    using (IEnumerator<TSource> e = source.GetEnumerator())
    {
        if (e.MoveNext()) return false; //second change
    }
    return true; //third change
}

1

Enumerable.Empty<T>()सूचियों के साथ उपयोग करने में एक खामी है। यदि आप Enumerable.Empty<T>सूची निर्माणकर्ता को सौंपते हैं तो आकार 4 की एक सरणी आवंटित की जाती है। लेकिन यदि आप Collectionसूची निर्माणकर्ता को खाली हाथ देते हैं तो कोई आवंटन नहीं होता है। इसलिए यदि आप अपने कोड में इस समाधान का उपयोग करते हैं, तो सबसे अधिक संभावना है कि किसी एक का IEnumerableउपयोग सूची बनाने के लिए किया जाएगा, जिसके परिणामस्वरूप अनावश्यक आवंटन होगा।

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