2010-06-28 11 views
9

मैं हमेशा सोचा है कि लौटने सरणी जब एक सार्वजनिक एपीआई होने सूचियों से बेहतर थे में वापस जाने के लिए सबसे अच्छा संग्रह प्रकार क्या है, लेकिन यह अब लगता है कि LINQ माध्यम से उपलब्ध हैं सूची में इन सभी कार्यों, आदिएक API

हैं

क्या प्राइमेटिव्स या ऑब्जेक्ट्स के संग्रह को वापस करने के लिए यहां सबसे अच्छा अभ्यास बदल गया है?

उदाहरण के लिए

:

Order[] GetOrders(); 
List<Order> GetOrders(); 
IEnumerable<Order> GetOrders(); 
IQueryable<Order> Get Orders(); 
+0

ध्यान दें कि उपर्युक्त सभी प्रकार लिनक को अलग-अलग डिग्री के लिए समर्थन देते हैं, या तो 'IENumerable ' या 'IQueryable ' के माध्यम से। –

उत्तर

5

मुझे लगता है कि सबसे अधिक इस्तेमाल किया प्रकार IEnumerable<T>

    एक IEnumerable<T> वापसी प्रकार आप yield कीवर्ड का उपयोग कर सकते हैं
  • है और इस देरी गणना करने और अपने विधि के निष्पादन के लिए सक्षम बनाता है । (उदाहरण के लिए एक आम शिकायत यह है कि System.IO.Path.GetFiles() IEnumerable<T> वापस नहीं लौटाता है लेकिन एक ऐरे देता है जिसका अर्थ है कि जब आप विधि को कॉल करते हैं तो सभी आइटमों को गिनने की आवश्यकता होती है, भले ही आपको उनकी आवश्यकता हो या नहीं। - आप) List<T> के साथ एक ही नुकसान
  • अधिकांश LINQ विस्तार तरीकों एक IEnumerable<T>
  • IEnumerable<T> वापसी प्रकार पर काम कुछ भी फोन करने वाले के बारे में विशिष्ट स्वीकार नही करता है। अगर कॉलर को एक सूची या सरणी की आवश्यकता होती है तो वे हमेशा एक बना सकते हैं।
  • IEnumerable<T>List<T> और Array द्वारा लागू किया गया है और इसलिए यह आपकी विधि के कार्यान्वयन को बदलने में आसान है और अभी भी पिछले रिटर्न प्रकार का समर्थन करता है।
+0

बस यह सुनिश्चित करें कि आप किसी को अपने 'आईनेमरेबल ' को कास्ट करने की अनुमति न दें, उदाहरण के लिए, 'सूची ' और इसे बदलें यदि वह कक्षा के आविष्कार को तोड़ देगा। अधिक जानकारी के लिए मेरा जवाब देखें। –

5

क्या आप संग्रह को अपरिवर्तनीय बनाना चाहते हैं? IEnumerable<T> उत्परिवर्ती? IList<T>

क्या आपको इंडेक्स की आवश्यकता है? IList<T>

एक सूची या सरणी के साथ

, एपीआई उपभोक्ता, जोड़ने के लिए निकालें, हटाएँ, स्पष्ट पूर्ण क्षमता, आदि

एक IEnumerable<T> साथ

है, एपीआई उपभोक्ता कोई विशेष के साथ, एक आइटम के "बैग" हो जाता है ऑर्डर, कोई इंडेक्स नहीं, और संग्रह को संशोधित करने के लिए कोई तरीका नहीं है।

कुछ सीमित परिस्थितियां हैं जिनमें आप IQueryable<T> वापस लौटना चाहेंगे, लेकिन वे अक्सर प्रश्न टुकड़े बनाने के लिए विशिष्ट होते हैं।

सामान्य रूप से, मैं IEnumerable<T> पर डिफ़ॉल्ट होगा। मैं एक बैकिंग फ़ील्ड के रूप में List<T> का उपयोग कर सकता हूं, लेकिन केवल उपयोगकर्ता को Add() पर अनुमति देना चाहता हूं, उदाहरण के लिए - निकालने, साफ़ करने या कुछ और नहीं, इसलिए मैं public void Add<T>(T item) घोषित करता हूं जो आइटम को बैकिंग फ़ील्ड सूची में जोड़ता है।

+0

यदि आपको इंडेक्स की आवश्यकता नहीं है तो ICollection के बारे में न भूलें। IList आईसीओलेक्शन लागू करता है और केवल एक इंडेक्सर, इंडेक्सऑफ (टी आइटम), सम्मिलित करें (इंट इंडेक्स, टी आइटम) और RemoveAt (int अनुक्रमणिका) जोड़ता है। –

1

दूसरों के कहने के अलावा मैं यह भी जोड़ना चाहता हूं कि आपको कभी भी IQueryable वापस नहीं करना चाहिए जब तक आप कुछ रिमोट डेटासोर्स से ऑब्जेक्ट्स को पुनर्प्राप्त नहीं कर लेते। IQueryable एक क्वेरी ऑब्जेक्ट है जो कॉलर की तरफ से परिणाम लाएगा। LINQ का उपयोग करते समय, एक IQuearyable आमतौर पर एक अभिव्यक्ति वृक्ष लेगा जिसका उपयोग किसी अन्य सिस्टम (उदा। एसक्यूएल सर्वर) द्वारा उपयोग के लिए किया जाएगा। अधिक जानकारी के लिए

http://weblogs.asp.net/fredriknormen/archive/2008/12/01/returning-iqueryable-lt-t-gt.aspx देखें।

5

जैसा कि मैं आम तौर पर केवल गुण/विधियों से अपरिवर्तनीय (अप्रचलित) वस्तुएं लौटाता हूं, यह उत्तर मानता है कि आप ऐसा करना चाहते हैं।

ReadOnlyCollection<T> को न भूलें जो एक अपरिवर्तनीय संग्रह लौटाता है जिसे अभी भी अनुक्रमणिका द्वारा एक्सेस किया जा सकता है।

आप IEnumerable<T> का उपयोग कर और बेकाबू जंगल में अपने प्रकार जारी कर रहे हैं, तो इस से सावधान रहना:

:

class MyClass { 
    private List<int> _list; 
    public IEnumerable<int> Numbers { 
     get { return _list; } 
    } 
} 

कोई उपयोगकर्ता इस और गंदगी अपने वर्ग की आंतरिक स्थिति के रूप में कर सकता है

var list = (List<int>)myClass.Numbers; 
list.Add(123); 

यह संपत्ति के लिए केवल पढ़ने के इरादे का उल्लंघन करेगा। ऐसे मामलों में, अपने गेटर इस तरह दिखना चाहिए:

public IEnumerable<int> Numbers { 
     get { return new ReadOnlyCollection<int>(_list); } 
    } 

वैकल्पिक रूप से आप _list.ToReadOnly() कह सकते हैं। मैंने इसे दिखाने के लिए इसे पूरी तरह से लिखा था।

इससे आपके राज्य को संशोधित करने से रोक दिया जाएगा (जब तक वे प्रतिबिंब का उपयोग नहीं करते हैं, लेकिन जब तक आप कई कार्यात्मक प्रोग्रामिंग भाषाओं में उपयोग करने वाले अपरिवर्तनीय संग्रह नहीं बनाते, तब तक यह वास्तव में कठिन होता है, और यह एक पूरी कहानी है)।

यदि आप केवल संग्रह पढ़ रहे हैं, तो आप सदस्य को ReadOnlyCollection<T> के रूप में घोषित करने से बेहतर हैं क्योंकि कुछ कार्य तेजी से प्रदर्शन करते हैं (गिनती प्राप्त करना, इंडेक्स द्वारा आइटम एक्सेस करना, किसी अन्य संग्रह में कॉपी करना)।

व्यक्तिगत तौर पर मैं इस तरह के ढांचे में शामिल हैं देख सकते हैं और एक इंटरफ़ेस का उपयोग करना चाहते हैं:

public interface IReadOnlyCollection<T> : IEnumerable<T> 
{ 
    T this[int index] { get; } 
    int Count { get; } 
    bool Contains(T item); 
    void CopyTo(T[] array, int arrayIndex); 
    int IndexOf(T item); 
} 

आप इन सभी IEnumerable<T> की चोटी पर विस्तार तरीकों का उपयोग कर कार्यों प्राप्त कर सकते हैं, लेकिन वे के रूप में performant नहीं कर रहे हैं।