2008-08-19 15 views
152

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

उत्तर

141

दो नियम नहीं हैं मैं का पालन करें:

  • सबसे बुनियादी प्रकार है कि
  • वापसी काम करेंगे स्वीकार सबसे अमीर टाइप जब एक समारोह या विधि लेखन अपने उपयोगकर्ता

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

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

+32

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

+11

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

+2

आपकी सुविधा के लिए, "दो नियमों" का नाम है: [मजबूती सिद्धांत (उर्फ पोस्टेल का कानून)] (https: // en .wikipedia.org/wiki/Robustness_principle)। – easoncxz

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

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

+0

मैं सहमत हूं, अगर आप स्पष्ट रूप से सूची ऑब्जेक्ट बना रहे हैं तो आप इंटरफ़ेस का लाभ खो देते हैं? –

1

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

आमतौर पर मैं सिर्फ यह एक तर्क के रूप में एक विधि

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

करने के लिए उपयोग, जब तक यह IEnumerable और नहीं IList है, जो होता है का उपयोग करता है यह, मुझे नेट ढांचे में लगभग किसी भी सरणी पर सामान्य प्रसंस्करण करने की अनुमति देगा कभी कभी।

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

5

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

1

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

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

9

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

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

+1

** ** सबसे कम बेस प्रकार संभव ** स्वीकार करना हमेशा सर्वोत्तम होता है। वापसी एक अलग कहानी है। चुनें कि कौन से विकल्प उपयोगी होने की संभावना है। तो आपको लगता है कि आपका ग्राहक अनुक्रमित पहुंच का उपयोग करना चाह सकता है? उन्हें 'toList()' से हटाएं- आपके लौटाए गए 'IENumerable ' जो कि पहले से ही एक सूची थी, और इसके बजाए 'IList ' वापस लौटाएं। अब, ग्राहक बिना किसी प्रयास के प्रदान कर सकते हैं से लाभ उठा सकते हैं। – Timo

24

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

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

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

50

माइक्रोसॉफ्ट दिशा निर्देशों FxCop द्वारा जाँच के रूप में सार्वजनिक APIs में सूची < टी > के उपयोग को हतोत्साहित - IList < टी > पसंद करते हैं।

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

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

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

+0

संबंधित: http://stackoverflow.com/questions/5968708/why-array-implements-ilist – Panzercrisis

3

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

हालांकि, .NET 2.0 में, एक परेशान चीज है - IList के पास सॉर्ट नहीं है() विधि।

ArrayList.Adapter(list).Sort() 
16

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

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

सूची सूची IList

+2

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

2

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

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

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

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

List<string> MyList = new List<string> 
24

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

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

:

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

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

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

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

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

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

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

+0

यह प्रत्येक इंटरफ़ेस के लिए यह सचमुच सच है। यदि आप के साथ अपने तर्क का पालन करना चाहते हैं, तो आप किसी भी इंटरफेस का कभी भी उपयोग नहीं करने के लिए बहस कर सकते हैं, क्योंकि इसके कुछ कार्यान्वयन फेंक सकते हैं। यदि आप, दूसरी तरफ, ओपी द्वारा दिए गए सुझाव पर विचार करें 'सूची '' IList 'से अधिक', आपको भी होना चाहिए क्योंकि' IList ' की अनुशंसा की जाती है। (उदाहरण के लिए https://blogs.msdn.microsoft.com/kcwalina/2005/09/26/why-we-dont-recommend-using-listt-in-public-apis/) –

+0

@MichaWiedenmann मेरा उत्तर यहां विशिष्ट है जब आप 'IList पर कॉल कर रहे हैं .एड() '। मैं यह नहीं कह रहा हूं कि * आपको 'IList ' का उपयोग नहीं करना चाहिए - मैं बस एक संभावित पतन को इंगित कर रहा हूं। (मैं 'आईएनयूमेरेबल ' या 'आईआरएडऑनलीलिस्ट ' या 'आईआरआईडीऑनली कोलेक्शन ' 'IList ' प्राथमिकता में 'अगर मैं कर सकता हूं) का उपयोग करता हूं।) –

संबंधित मुद्दे