IList का उपयोग कब करें और लिस्ट का उपयोग कब करें


180

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


1
अगर कोई अभी भी सोच रहा है, तो मुझे यहाँ सबसे अच्छे उत्तर मिले: stackoverflow.com/questions/400135/listt-or-ilistt
Crismogram

जवाबों:


175

मेरे दो नियम हैं:

  • सबसे बुनियादी प्रकार को स्वीकार करें जो काम करेगा
  • सबसे अमीर प्रकार लौटाएं, जिसकी आपके उपयोगकर्ता को आवश्यकता होगी

इसलिए जब एक समारोह या विधि जो एक संग्रह लेती है, तो इसे एक सूची में न लेने के लिए लिखें, लेकिन एक इलिस्ट <टी>, एक ICollection <T>, या IEnumerable <T>। सामान्य इंटरफेस अभी भी विषम सूचियों के लिए भी काम करेगा क्योंकि System.Object एक T भी हो सकता है। ऐसा करने से आप सिरदर्द से बच जाएंगे यदि आप सड़क के नीचे एक स्टैक या कुछ अन्य डेटा संरचना का उपयोग करने का निर्णय लेते हैं। यदि आपको फ़ंक्शन में सभी करने की आवश्यकता है, तो इसके माध्यम से फॉर्च्यूनर है, IEnumerable <T> वास्तव में आप के लिए पूछ रहे हैं।

दूसरी ओर, जब आप किसी फ़ंक्शन से बाहर लौटते हैं, तो आप उपयोगकर्ता को चारों ओर कास्ट किए बिना ऑपरेशन के सबसे अमीर संभव सेट देना चाहते हैं। तो उस स्थिति में, यदि यह एक सूची है <T> आंतरिक रूप से, सूची <T> के रूप में एक प्रति लौटाएं।


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

11
मैं 2 नियमों से असहमत हूं ... मैं इस मामले में लौटते समय सबसे आदिम प्रकार और विशेष का उपयोग करूंगा। इलिस्ट (बेहतर IEnumarable) और आपको अपने फ़ंक्शन में सूची के साथ काम करना चाहिए। फिर जब आपको "ऐड" या "सॉर्ट" की आवश्यकता होती है तब संग्रह का उपयोग करें यदि अधिक आवश्यकता हो तो सूची का उपयोग करें। तो मेरा कठिन नियम होगा: START हमेशा IENumarable के साथ और अगर आपको और अधिक की आवश्यकता है तो विस्तार करें ...
ethem

2
आपकी सुविधा के लिए, "दो नियमों" में एक नाम है: मजबूती सिद्धांत (उर्फ पोस्टेल का नियम)
easoncxz

बहस के पक्ष में जो किसी के बारे में सबसे बुनियादी प्रकार या सबसे अमीर प्रकार को वापस करने के लिए है, इस पर विचार करने के लिए कुछ है कि बहुत ही सरलीकृत इंटरफ़ेस वापस करते समय, खपत कोड बार-बार हो सकता है - हालांकि हमेशा नहीं - आकृति के if...elseलिए isकीवर्ड के साथ एक श्रृंखला का उपयोग करें इसके लिए एक बहुत अमीर प्रकार है और अंत में इसे कास्टिंग करना और वैसे भी उपयोग करना है। इसलिए आपको जरूरी नहीं कि किसी बुनियादी इंटरफ़ेस का उपयोग करके कुछ भी छिपाने की गारंटी दी जाए, बजाय इसके केवल अस्पष्ट के। हालाँकि इसे कठिन बनाने से उपभोगकर्ता कोड के लेखक को दो बार सोचना पड़ सकता है कि वे इसका उपयोग कैसे कर रहे हैं।
पैन्ज़रक्रिसिस

6
मैं प्वाइंट # 2 के बारे में बहुत असहमत हूं, खासकर अगर यह एक सेवा / एपीआई सीमा पर है। परिवर्तनीय संग्रह लौटा देने से यह आभास हो सकता है कि संग्रह "लाइव" और कॉलिंग के तरीके हैं Add()और Remove()केवल संग्रह से परे प्रभाव हो सकते हैं। केवल-पढ़ने के लिए इंटरफ़ेस को वापस करना जैसे कि IEnumerableअक्सर डेटा-पुनर्प्राप्ति विधियों के लिए जाना जाता है। आपका उपभोक्ता इसे एक समृद्ध प्रकार में आवश्यकतानुसार प्रोजेक्ट कर सकता है।
STW

56

सार्वजनिक दिशानिर्देशों में सूची <T> के FxCop द्वारा उपयोग को हतोत्साहित करने के रूप में Microsoft दिशानिर्देश - IList <T> को प्राथमिकता दें।

संयोग से, मैं अब लगभग हमेशा एक-आयामी सरणियों को IList <T> घोषित करता हूं, जिसका अर्थ है कि मैं लगातार IList <T> का उपयोग कर सकता हूं। Array.Length की बजाय संपत्ति। उदाहरण के लिए:

public interface IMyApi
{
    IList<int> GetReadOnlyValues();
}

public class MyApiImplementation : IMyApi
{
    public IList<int> GetReadOnlyValues()
    {
        List<int> myList = new List<int>();
        ... populate list
        return myList.AsReadOnly();
    }
}
public class MyMockApiImplementationForUnitTests : IMyApi
{
    public IList<int> GetReadOnlyValues()
    {
        IList<int> testValues = new int[] { 1, 2, 3 };
        return testValues;
    }
}

3
मुझे यह स्पष्टीकरण पसंद है / उदाहरण सबसे!
जॉन 12

28

एक महत्वपूर्ण बात यह है कि लोग हमेशा अनदेखी करने लगते हैं:

आप एक सादे सरणी को किसी ऐसी चीज से पारित कर सकते हैं जो एक IList<T>पैरामीटर को स्वीकार करती है , और फिर आप कॉल कर सकते हैं IList.Add()और एक रनटाइम अपवाद प्राप्त करेंगे:

Unhandled Exception: System.NotSupportedException: Collection was of a fixed size.

उदाहरण के लिए, निम्नलिखित कोड पर विचार करें:

private void test(IList<int> list)
{
    list.Add(1);
}

यदि आप निम्नानुसार कॉल करते हैं, तो आपको एक रनटाइम अपवाद मिलेगा:

int[] array = new int[0];
test(array);

ऐसा इसलिए होता है क्योंकि IList<T>लिसकोव प्रतिस्थापन सिद्धांत के उल्लंघन के साथ सादे सरणियों का उपयोग करना।

इस कारण से, यदि आप कॉल कर रहे हैं, तो आप इसके बजाय IList<T>.Add()एक की आवश्यकता पर विचार करना चाह सकते हैं ।List<T>IList<T>


यह प्रत्येक इंटरफ़ेस के लिए तुच्छ रूप से सत्य है। यदि आप अपने तर्क के माध्यम से पालन करना चाहते हैं, तो आप किसी भी इंटरफ़ेस को कभी भी उपयोग न करने का तर्क दे सकते हैं, क्योंकि इसका कुछ कार्यान्वयन फेंक सकता है। यदि आप दूसरी ओर, ओपी द्वारा दिए गए सुझाव पर विचार करना पसंद करते List<T>हैं IList<T>, तो आपको उन कारणों के बारे में भी पता होना चाहिए जिनकी IList<T>सिफारिश की गई है। (उदाहरण के लिए blogs.msdn.microsoft.com/kcwalina/2005/09/26/… )
Micha Wiedenmann

3
@MichaWiedenmann मेरा उत्तर यहाँ विशिष्ट है जब आप बुला रहे हैं IList<T>.Add()। मैं यह नहीं कह रहा हूं कि आपको उपयोग नहीं करना चाहिएIList<T> - मैं सिर्फ एक संभावित नुकसान की ओर इशारा कर रहा हूं। (मैं का उपयोग करते हैं IEnumerable<T>या IReadOnlyList<T>या IReadOnlyCollection<T>वरीयता में करने के लिए IList<T>अगर मैं कर सकते हैं।)
मैथ्यू वाटसन

24

मैं मापदंडों को लेने के लिए ली की सलाह से सहमत हूं, लेकिन वापस नहीं।

यदि आप एक इंटरफ़ेस वापस करने के लिए अपने तरीकों को निर्दिष्ट करते हैं, जिसका अर्थ है कि आप बाद में कभी भी उपभोग करने वाले तरीके के बिना सटीक कार्यान्वयन को बदलने के लिए स्वतंत्र हैं। मैंने सोचा था कि मुझे कभी सूची <T> से बदलने की आवश्यकता नहीं होगी, लेकिन बाद में इसे प्रदान की गई अतिरिक्त कार्यक्षमता के लिए एक कस्टम सूची लाइब्रेरी का उपयोग करने के लिए बदलना होगा। क्योंकि मैं केवल एक IList <T> लौटा हूं, लेकिन पुस्तकालय का उपयोग करने वाले लोगों में से किसी को भी अपना कोड बदलना नहीं था।

बेशक, केवल उन तरीकों पर लागू होने की आवश्यकता है जो बाहरी रूप से दिखाई देते हैं (यानी सार्वजनिक तरीके)। मैं आंतरिक कोड में भी व्यक्तिगत रूप से इंटरफेस का उपयोग करता हूं, लेकिन जब आप ब्रेकिंग परिवर्तन करते हैं तो आप सभी कोड को स्वयं बदल सकते हैं।


22

IEnumerable
आपको कोशिश करनी चाहिए और कम से कम विशिष्ट प्रकार का उपयोग करना चाहिए जो आपके उद्देश्य के अनुरूप हो।
IEnumerableसे कम विशिष्ट है IList। जब आप किसी संग्रह में आइटम के माध्यम से लूप करना चाहते
हैं IEnumerableतो आप उपयोग करते हैं।

IList
IList लागू करता है IEnumerable। जब आपको अपने संग्रह में सूचकांक द्वारा पहुंच की आवश्यकता होती है, तो आपको तत्वों को जोड़ने और हटाने आदि का
उपयोग करना चाहिए IList...

सूची
List लागू करें IList


3
उत्कृष्ट, स्पष्ट उत्तर, जिसे मैंने सहायक के रूप में चिह्नित किया है। हालाँकि, मुझे लगता है कि ज्यादातर डेवलपर्स के लिए, ज्यादातर समय, कार्यक्रम के आकार और प्रदर्शन में छोटे अंतर के बारे में चिंता करने योग्य नहीं है: यदि संदेह है, तो बस एक सूची का उपयोग करें।
ग्राहम नाइट

9

हमेशा सबसे कम बेस प्रकार का उपयोग करना सबसे अच्छा होता है। यह आपके इंटरफ़ेस के कार्यान्वयनकर्ता, या आपकी पद्धति के उपभोक्ता को, पर्दे के पीछे जो कुछ भी उन्हें पसंद है उसका उपयोग करने का अवसर देता है।

संग्रह के लिए आपको जहाँ संभव हो IEnumerable का उपयोग करने का लक्ष्य रखना चाहिए। यह सबसे अधिक लचीलापन देता है लेकिन हमेशा अनुकूल नहीं होता है।


1
हमेशा सबसे कम बेस प्रकार को स्वीकार करना सबसे अच्छा है। लौटना एक अलग कहानी है। चुनें कि क्या विकल्प उपयोगी होने की संभावना है। तो आपको लगता है कि आपके ग्राहक अनुक्रमित पहुंच का उपयोग करना चाहते हैं? उन्हें ToList()अपने-अपने लौटे से रखें IEnumerable<T>जो पहले से ही एक सूची थी, और IList<T>इसके बजाय वापस लौटें । अब, क्लाइंट बिना किसी प्रयास के आपको जो कुछ भी प्रदान कर सकते हैं उससे लाभान्वित हो सकते हैं।
तिमो

5

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


4

मुझे नहीं लगता कि इस प्रकार की चीज़ों के लिए कठिन और तेज़ नियम हैं, लेकिन मैं आमतौर पर बिल्कुल आवश्यक तरीके से सबसे हल्का संभव तरीके का उपयोग करने के दिशानिर्देश द्वारा जाता हूं।

उदाहरण के लिए, मान लें कि आपके पास एक Personवर्ग और एक Groupवर्ग है। एक Groupउदाहरण में कई लोग हैं, इसलिए यहां एक सूची समझ में आएगी। जब मैं सूची ऑब्जेक्ट को घोषित करता हूं तो मैं Groupइसका उपयोग करूंगा IList<Person>और इसे एक के रूप में त्वरित करूंगा List

public class Group {
  private IList<Person> people;

  public Group() {
    this.people = new List<Person>();
  }
}

और, अगर आप भी सब कुछ की जरूरत नहीं है IListआप हमेशा IEnumerableभी उपयोग कर सकते हैं। आधुनिक संकलक और प्रोसेसर के साथ, मुझे नहीं लगता कि वास्तव में कोई गति अंतर है, इसलिए यह सिर्फ स्टाइल की बात है।


3
क्यों नहीं यह पहली जगह में सिर्फ एक सूची है? मुझे अभी भी समझ में नहीं आया है कि बोनस आपको इसे IList बनाने से क्यों मिलता है, तो कंस्ट्रक्टर में आप इसे एक लिस्ट में बनाते हैं <>
chobo2

मैं सहमत हूं, यदि आप स्पष्ट रूप से एक सूची <T> ऑब्जेक्ट बना रहे हैं तो आप इंटरफ़ेस का लाभ खो देते हैं?
The_Butcher

4

आप सबसे अधिक सामान्य प्रयोग करने योग्य प्रकार का उपयोग करने के लिए अक्सर बेहतर होते हैं, इस मामले में IList या इससे भी बेहतर IEnumerable इंटरफ़ेस, ताकि आप कार्यान्वयन को बाद के समय में आसानी से बदल सकें।

हालाँकि, .NET 2.0 में, एक कष्टप्रद बात है - IList में एक सॉर्ट () विधि नहीं है। आप इसके बजाय एक आपूर्ति एडाप्टर का उपयोग कर सकते हैं:

ArrayList.Adapter(list).Sort()

2

आपको इंटरफ़ेस का उपयोग केवल तभी करना चाहिए जब आपको इसकी आवश्यकता हो, उदाहरण के लिए, यदि आपकी सूची सूची से इतर IList कार्यान्वयन के लिए डाली गई है। यह सच है जब, उदाहरण के लिए, आप NHibernate का उपयोग करते हैं, जो डेटा प्राप्त करते समय ILists को NHibernate बैग ऑब्जेक्ट में डाल देता है।

यदि सूची एकमात्र कार्यान्वयन है जिसे आप कभी भी एक निश्चित संग्रह के लिए उपयोग करेंगे, तो इसे एक ठोस सूची कार्यान्वयन के रूप में घोषित करने के लिए स्वतंत्र महसूस करें।


1

जिन स्थितियों में मैं आमतौर पर आता हूं, मैं शायद ही कभी इलिस्ट का उपयोग करता हूं।

आमतौर पर मैं इसे एक विधि के तर्क के रूप में उपयोग करता हूं

void ProcessArrayData(IList almostAnyTypeOfArray)
{
    // Do some stuff with the IList array
}

यह मुझे .NET फ्रेमवर्क में लगभग किसी भी सरणी पर सामान्य प्रसंस्करण करने की अनुमति देगा, जब तक कि यह IEnumerable और IList का उपयोग नहीं करता है, जो कभी-कभी होता है।

यह वास्तव में उस प्रकार की कार्यक्षमता के लिए आता है जिसकी आपको आवश्यकता है। मैं ज्यादातर मामलों में सूची वर्ग का उपयोग करने का सुझाव दूंगा। IList तब सर्वोत्तम होता है जब आपको एक कस्टम एरे बनाने की आवश्यकता होती है जिसमें कुछ बहुत ही विशिष्ट नियम हो सकते हैं जिन्हें आप एक संग्रह के भीतर इनकैप्सूलेट करना चाहते हैं ताकि आप अपने आप को दोहराएं नहीं, लेकिन फिर भी .NET को सूची के रूप में पहचानना चाहते हैं।


1

एलिस्ट ऑब्जेक्ट आपको एक सूची बनाने, उसमें चीजें जोड़ने, उसे हटाने, उसे अपडेट करने, उसमें इंडेक्स करने और आदि का उपयोग करने की अनुमति देता है। सूची का उपयोग तब किया जाता है जब आप बस एक सामान्य सूची चाहते हैं, जहां आप इसमें ऑब्जेक्ट प्रकार निर्दिष्ट करते हैं और यह बात है।

दूसरी ओर IList एक इंटरफ़ेस है। मूल रूप से, यदि आप अपनी स्वयं की सूची बनाना चाहते हैं, तो एक सूची वर्ग कहें, जिसे बुकलिस्ट कहा जाता है, तो आप अपने नए वर्ग को बुनियादी तरीके और संरचना देने के लिए इंटरफ़ेस का उपयोग कर सकते हैं। IList तब होता है जब आप अपना स्वयं का, विशेष उप-वर्ग बनाना चाहते हैं जो सूची को लागू करता है।

एक और अंतर है: IList एक इंटरफ़ेस है और इसे तत्काल नहीं बनाया जा सकता है। सूची एक वर्ग है और इसे त्वरित किया जा सकता है। इसका मतलब:

IList<string> MyList = new IList<string>();

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