संग्रह <टी> बनाम सूची <टी> आपको अपने इंटरफेस पर क्या उपयोग करना चाहिए?


162

कोड नीचे की तरह दिखता है:

namespace Test
{
    public interface IMyClass
    {
        List<IMyClass> GetList();
    }

    public class MyClass : IMyClass
    {
        public List<IMyClass> GetList()
        {
            return new List<IMyClass>();
        }
    }
}

जब मैं कोड विश्लेषण चलाता हूं तो मुझे निम्नलिखित अनुशंसा मिलती है।

चेतावनी 3 CA1002: Microsoft.Design: संग्रह, ReadOnlyCollection या KeyedCollection का उपयोग करने के लिए 'IMyClass.GetList ()' में 'सूची' बदलें।

मुझे इसे कैसे ठीक करना चाहिए और यहां अच्छा अभ्यास क्या है?

जवाबों:


234

प्रश्न का "क्यों" भाग का उत्तर देने के लिए क्यों नहीं List<T>, इसका कारण भविष्य के प्रमाण और एपीआई सादगी हैं।

भविष्य प्रूफिंग

List<T>इसे उप-वर्ग द्वारा आसानी से एक्स्टेंसिबल करने के लिए डिज़ाइन नहीं किया गया है; यह आंतरिक कार्यान्वयन के लिए तेज़ होने के लिए डिज़ाइन किया गया है। आप इस पर ध्यान देंगे कि विधियाँ आभासी नहीं हैं और इसलिए इसे ओवरराइड नहीं किया जा सकता है, और इसके Add/ Insert/ Removeसंचालन में कोई हुक नहीं हैं ।

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

इसलिए या तो एक ऐसे वर्ग को लौटाया जा सकता है, जिसे आसानी से उप-वर्ग में रखा जा सकता है जैसे कि Collection<T>या एक इंटरफ़ेस जैसे IList<T>, ICollection<T>या IEnumerable<T>आप अपनी आंतरिक कार्यान्वयन को अपनी आवश्यकताओं को पूरा करने के लिए एक अलग संग्रह प्रकार के रूप में बदल सकते हैं, उपभोक्ताओं के कोड को तोड़े बिना, क्योंकि इसे अभी भी लौटाया जा सकता है। प्रकार वे उम्मीद कर रहे हैं।

एपीआई सादगी

List<T>इसमें बहुत सारे उपयोगी संचालन शामिल हैं जैसे कि BinarySearch, Sortऔर इसी तरह। हालाँकि यदि यह एक संग्रह है जिसे आप उजागर कर रहे हैं तो यह संभावना है कि आप सूची के शब्दार्थ को नियंत्रित करते हैं, न कि उपभोक्ताओं को। इसलिए जब आपकी कक्षा को आंतरिक रूप से इन कार्यों की आवश्यकता हो सकती है, तो यह बहुत कम संभावना है कि आपके वर्ग के उपभोक्ता उन्हें (या यहां तक ​​कि) उन्हें कॉल करना चाहते हैं।

जैसे, एक सरल संग्रह वर्ग या इंटरफ़ेस की पेशकश करके, आप उन सदस्यों की संख्या कम कर देते हैं जिन्हें आपके API के उपयोगकर्ता देखते हैं, और उनका उपयोग करना आसान बनाते हैं।


1
यह प्रतिक्रिया मृत है। विषय पर एक और अच्छा पढ़ा यहाँ पाया जा सकता है: blogs.msdn.com/fxcop/archive/2006/04/27/…
senfo

7
मुझे आपके पहले अंक दिखाई देते हैं, लेकिन मुझे नहीं पता कि मैं आपके एपीआई सादगी वाले हिस्से पर सहमत हूं।
बोरिस कॉल

stackoverflow.com/a/398988/2632991 यहां एक वास्तविक अच्छी पोस्ट भी है, जो कि संग्रह और सूचियों के बीच अंतर है।
एल मैक

2
blogs.msdn.com/fxcop/archive/2006/04/27/… -> मृत है। क्या हमारे पास इसके लिए एक नई जानकारी है?
मचाडो


50

मैं व्यक्तिगत रूप से इसे एक ठोस संग्रह के बजाय एक इंटरफ़ेस वापस करने की घोषणा करूंगा। यदि आप वास्तव में सूची एक्सेस चाहते हैं, तो उपयोग करें IList<T>। अन्यथा, विचार करें ICollection<T>और IEnumerable<T>


1
क्या IList तब ICollection इंटरफ़ेस का विस्तार करेगा?
बोवियम

8
@Jon: मुझे पता है कि यह पुराना है, लेकिन क्या आप इस बारे में टिप्पणी कर सकते हैं कि Blogzmsdn.com/b/kcwalina/archive/2005/09/26/474010.aspx पर Krzysztof क्या कहते हैं ? विशेष रूप से उनकी टिप्पणी, We recommend using Collection<T>, ReadOnlyCollection<T>, or KeyedCollection<TKey,TItem> for outputs and properties and interfaces IEnumerable<T>, ICollection<T>, IList<T> for inputs. CA1002 Krzysztof की टिप्पणियों के साथ जाना प्रतीत होता है। मैं कल्पना नहीं कर सकता कि एक इंटरफ़ेस के बजाय एक ठोस संग्रह की सिफारिश क्यों की जाएगी, और इनपुट / आउटपुट के बीच अंतर क्यों है।
नेल्सन रॉथमेल

3
@ नेल्सन: यह दुर्लभ है कि आप अपरिवर्तनीय सूची में पास होने के लिए कॉलर्स की आवश्यकता चाहते हैं , लेकिन यह एक वापसी के लिए उचित है ताकि उन्हें पता चले कि यह निश्चित रूप से अपरिवर्तनीय है। हालांकि अन्य संग्रह के बारे में निश्चित नहीं है। अधिक विवरण के लिए अच्छा होगा।
जॉन स्कीट

2
यह एक विशिष्ट मामले के लिए नहीं है। जाहिर है सामान्य रूप से ReadOnlyCollection<T>एक इनपुट के लिए कोई मतलब नहीं होगा। इसी तरह, IList<T>जैसा कि एक इनपुट कहता है, "मुझे सॉर्ट () या किसी अन्य सदस्य की आवश्यकता है जो एक IList के पास है" जो आउटपुट के लिए समझ में नहीं आता है। लेकिन मेरा मतलब था कि ICollection<T>इनपुट के Collection<T>रूप में और आउटपुट के रूप में सिफारिश क्यों की जाएगी । जैसा कि आपने सुझाव दिया था कि आउटपुट के रूप में भी इसका उपयोग क्यों नहींICollection<T> किया गया?
नेल्सन रॉदरमेल

9
मैं सोच रहा हूं कि इसका इनबिलिटी के साथ क्या करना है। Collection<T>और ReadOnlyCollection<T>दोनों ही ICollection<T>(अर्थात नहीं है IReadOnlyCollection<T>) से प्राप्त होते हैं । यदि आप इंटरफ़ेस वापस करते हैं, तो यह स्पष्ट नहीं है कि यह कौन सा है और क्या इसे संशोधित किया जा सकता है। वैसे भी, आपके इनपुट के लिए धन्यवाद। यह मेरे लिए एक अच्छी स्वच्छता जांच थी।
नेल्सन रॉदरमेल

3

मुझे नहीं लगता कि किसी ने "क्यों" भाग का जवाब अभी तक दिया है ... इसलिए यहाँ जाता है। इसका कारण "क्यों" आपको "एक" के Collection<T>बजाय का उपयोग करना चाहिए List<T>क्योंकि यदि आप एक को उजागर करते हैं List<T>, तो जो कोई भी आपकी वस्तु तक पहुंचता है, वह सूची में आइटम को संशोधित कर सकता है। जबकि Collection<T>यह संकेत दिया जाता है कि आप अपनी "Add", "Remove", आदि विधियाँ बना रहे हैं।

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

यदि आपके पास एक सार्वजनिक सरणी है, तो पूर्व:

public int[] MyIntegers { get; }

आपको लगता है कि क्योंकि वहाँ केवल एक "प्राप्त" गौण है कि कोई भी मूल्यों के साथ खिलवाड़ कर सकता है, लेकिन यह सच नहीं है। कोई भी इस तरह से अपने अंदर के मूल्यों को बदल सकता है:

someObject.MyIngegers[3] = 12345;

निजी तौर पर, मैं List<T>ज्यादातर मामलों में उपयोग करूंगा । लेकिन अगर आप एक क्लास लाइब्रेरी डिजाइन कर रहे हैं, जिसे आप यादृच्छिक डेवलपर्स को देने जा रहे हैं, और आपको वस्तुओं की स्थिति पर भरोसा करने की आवश्यकता है ... तो आप अपना खुद का संग्रह बनाना चाहेंगे और इसे वहां से बंद कर देंगे: )


"यदि आप क्लाइंट कोड में सूची <T> लौटाते हैं, तो आप कभी भी क्लाइंट कोड को संशोधित करते समय सूचनाएं प्राप्त नहीं कर पाएंगे।" - FX COP ... यह भी देखें " msdn.microsoft.com/en-us/library/0fss9skc.aspx " ... वाह, लगता है मैं सब के बाद बेस ऑफ नहीं हूं :)
टिमोथी खौरी

वाह - वर्षों बाद मैं देख रहा हूं कि उपरोक्त टिप्पणी में मैंने जो लिंक चिपकाया था, उसके अंत में एक उद्धरण था, इसलिए यह काम नहीं किया ... msdn.microsoft.com/en-us/library/0fss9skc.aspx
टिमोथी खौरी

2

यह सीधे सूची में हेरफेर किए जाने के बजाय अपने स्वयं के कार्यान्वयन को दूर करने के बारे में है।

अन्य वस्तुओं (या लोगों) को अपनी वस्तुओं की स्थिति को सीधे संशोधित करने देना अच्छा नहीं है। प्रॉपर्टी गेटर्स / सेटर्स के बारे में सोचें

संग्रह -> सामान्य संग्रह के लिए
ReadOnlyCollection -> ऐसे संग्रह के लिए जिन्हें संशोधित नहीं किया जाना चाहिए
KeyedCollection -> जब आप इसके बजाय शब्दकोश चाहते हैं।

इसे कैसे ठीक करें यह इस बात पर निर्भर करता है कि आप अपनी कक्षा को क्या करना चाहते हैं और गेटलिस्ट () पद्धति का उद्देश्य क्या है। क्या आप विस्तार से समझा सकते हैं?


1
लेकिन संग्रह <T> और KeyedCollection <,> या तो आसानी से पढ़े नहीं जाते हैं।
नवफ़ल

@nawfal और मैंने कहाँ कहा कि यह है?
चक्रित

1
आप अन्य वस्तुओं (या लोगों) को अपनी वस्तुओं की स्थिति को सीधे संशोधित नहीं करने देते हैं और 3 संग्रह प्रकारों को सूचीबद्ध करते हैं। ReadOnlyCollectionअन्य दो को छोड़कर इसका पालन नहीं करता है।
नवाफल

यह "अच्छा अभ्यास" की बात कर रहा है। कृपया उचित संदर्भ दें। नीचे दी गई सूची में इस प्रकार की मूलभूत आवश्यकता बताई गई है क्योंकि ओपी चेतावनी को समझना चाहता है। फिर मैं उससे इस उद्देश्य के बारे में पूछता हूं कि क्या GetList()वह अधिक सही ढंग से उसकी मदद कर सकता है।
चक्रित

1
ठीक है मैं उस हिस्से को समझता हूं। लेकिन फिर भी तर्क वाला हिस्सा मेरे मुताबिक नहीं है। आप कहते हैं कि Collection<T>आंतरिक कार्यान्वयन को रोकने में मदद करता है और आंतरिक सूची के प्रत्यक्ष हेरफेर को रोकता है। कैसे? Collection<T>केवल एक आवरण है, जो उसी उदाहरण पर संचालित होता है। यह विरासत के लिए एक गतिशील संग्रह है, और कुछ नहीं (ग्रेग का जवाब यहां अधिक प्रासंगिक है)।
नवफाल

1

इस तरह के मामले में मैं आमतौर पर कम से कम कार्यान्वयन की मात्रा को उजागर करने की कोशिश करता हूं जिसकी आवश्यकता है। यदि उपभोक्ताओं को यह जानने की आवश्यकता नहीं है कि आप वास्तव में एक सूची का उपयोग कर रहे हैं तो आपको सूची वापस करने की आवश्यकता नहीं है। Microsoft के रूप में वापस लौटने से आपको एक संग्रह का पता चलता है जो आप इस तथ्य को छिपाते हैं कि आप अपने वर्ग के उपभोक्ताओं की सूची का उपयोग कर रहे हैं और उन्हें आंतरिक परिवर्तन के खिलाफ अलग कर रहे हैं।


1

कुछ जोड़ने के लिए हालांकि यह एक लंबे समय के बाद से यह पूछा गया था।

जब आपकी सूची प्रकार List<T>इसके स्थान से प्राप्त होती है Collection<T>, तो आप संरक्षित वर्चुअल विधियों को Collection<T>लागू नहीं कर सकते हैं । इसका अर्थ यह है कि सूची में कोई संशोधन किए जाने पर आप व्युत्पन्न प्रकार का जवाब नहीं दे सकते। ऐसा इसलिए है क्योंकि List<T>जब आप आइटम जोड़ते या हटाते हैं तो आप अवगत होते हैं। सूचनाओं का जवाब देने में सक्षम होने के कारण यह ओवरहेड है और इसलिए List<T>इसे पेश नहीं करता है।

ऐसे मामलों में जब बाहरी कोड के पास आपके संग्रह तक पहुंच होती है, तब आप नियंत्रण में नहीं रह सकते हैं जब कोई आइटम जोड़ा या हटाया जा रहा हो। इसलिए Collection<T>यह जानने का एक तरीका प्रदान करता है कि आपकी सूची को कब संशोधित किया गया था।


0

मुझे कुछ वापस करने जैसी कोई समस्या नहीं दिख रही है

this.InternalData.Filter(crteria).ToList();

यदि मैंने आंतरिक डेटा की डिस्कनेक्ट की गई प्रति वापस कर दी है , या डेटा क्वेरी का अलग परिणाम दिया है - मैं List<TItem>किसी भी कार्यान्वयन विवरण को उजागर किए बिना सुरक्षित रूप से वापस आ सकता हूं , और सुविधाजनक तरीके से वापस किए गए डेटा का उपयोग करने की अनुमति दे सकता हूं ।

लेकिन यह इस बात पर निर्भर करता है कि मैं किस प्रकार के उपभोक्ता की उम्मीद करता हूं - अगर यह डेटा ग्रिड जैसा कुछ है तो मैं वापस लौटना पसंद करता हूं IEnumerable<TItem> जो कि ज्यादातर मामलों में वैसे भी वस्तुओं की कॉपी की गई सूची होगी :)


-1

खैर संग्रह वर्ग वास्तव में अपने कार्यान्वयन विवरण और अन्य विशेषताओं को छिपाने के लिए अन्य संग्रह के आसपास केवल एक आवरण वर्ग है। मुझे लगता है कि यह वस्तु उन्मुख भाषाओं में कोडिंग पैटर्न को छिपाने वाली संपत्ति के साथ कुछ करना है।

मुझे लगता है कि आपको इसके बारे में चिंता नहीं करनी चाहिए, लेकिन यदि आप वास्तव में कोड विश्लेषण उपकरण को खुश करना चाहते हैं, तो बस निम्नलिखित करें:

//using System.Collections.ObjectModel;

Collection<MyClass> myCollection = new Collection<MyClass>(myList);

1
क्षमा करें, यह एक टाइपो था। मैं मेनैट कलेक्शन <MyClass>। मैं वास्तव में C # 4 पर अपने हाथ पाने के लिए उत्सुक हूं और जेनेरिक covariance btw!
तमस Czinege

Collection<T>जहाँ तक मेरी समझ में है, न तो खुद को सुरक्षित रखना और न ही अंतर्निहित संग्रह को लपेटना ।
नवफाल

कोड का वह टुकड़ा "कोड विश्लेषण उपकरण को कृपया" था। मुझे नहीं लगता कि @TamasCzinege ने कहीं भी कहा कि उपयोग करने Collection<T>से आपके अंतर्निहित संग्रह की सुरक्षा तुरंत हो जाएगी।
चक्रित
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.