IList या सूची का उपयोग क्यों करें?


82

मुझे पता है कि इस पर बहुत सारी पोस्टें हैं लेकिन यह अभी भी मुझे भ्रमित करता है कि आपको आइलिस्ट जैसे इंटरफ़ेस में पास क्यों होना चाहिए और आईलैस्ट जैसे इंटरफ़ेस को ठोस सूची के बजाय वापस करना चाहिए।

मैंने बहुत सारी पोस्ट पढ़ीं कि यह कैसे कार्यान्वयन को बाद में बदलना आसान बनाता है, लेकिन मैं अभी पूरी तरह से नहीं देखता कि यह कैसे काम करता है।

कहो तो मेरे पास यह विधि है

  public class SomeClass
    {
        public bool IsChecked { get; set; }
    }

 public void LogAllChecked(IList<SomeClass> someClasses)
    {
        foreach (var s in someClasses)
        {
            if (s.IsChecked)
            {
                // log 
            }
        }
    }

मुझे यकीन नहीं है कि IList का उपयोग करने से मुझे भविष्य में कैसे मदद मिलेगी।

कैसे के बारे में अगर मैं पहले से ही विधि में हूं? क्या मुझे अभी भी IList का उपयोग करना चाहिए?

public void LogAllChecked(IList<SomeClass> someClasses)
    {
        //why not List<string> myStrings = new List<string>()
        IList<string> myStrings = new List<string>();

        foreach (var s in someClasses)
        {
            if (s.IsChecked)
            {
                myStrings.Add(s.IsChecked.ToString());
            }
        }
    }

अब मुझे IList का उपयोग करने के लिए क्या मिलेगा?

public IList<int> onlySomeInts(IList<int> myInts)
    {
        IList<int> store = new List<int>();
        foreach (var i in myInts)
        {
            if (i % 2 == 0)
            {
                store.Add(i);
            }
        }

        return store;
    }

अभी के बारे में कैसे? क्या इंट की सूची में कुछ नया कार्यान्वयन है जिसे मुझे बदलने की आवश्यकता होगी?

मूल रूप से, मुझे कुछ वास्तविक कोड उदाहरणों को देखने की आवश्यकता है कि कैसे IList का उपयोग करके सूची में सब कुछ लेने पर कुछ समस्या हल हो गई होगी।

मेरे पढ़ने से मुझे लगता है कि मैं IList के बजाय IEnumberable का उपयोग कर सकता था क्योंकि मैं सिर्फ सामान के माध्यम से पाशन कर रहा हूं।

संपादित करें तो मैं ऐसा करने के तरीके पर अपने तरीकों के कुछ के साथ चारों ओर खेल रहे हैं। मैं अभी भी वापसी प्रकार के बारे में निश्चित नहीं हूं (यदि मुझे इसे और अधिक ठोस या इंटरफ़ेस बनाना चाहिए)।

 public class CardFrmVm
    {
        public IList<TravelFeaturesVm> TravelFeaturesVm { get; set; }
        public IList<WarrantyFeaturesVm> WarrantyFeaturesVm { get; set; }

        public CardFrmVm()
        {
            WarrantyFeaturesVm = new List<WarrantyFeaturesVm>();
            TravelFeaturesVm = new List<TravelFeaturesVm>();
        }
}

 public class WarrantyFeaturesVm : AvailableFeatureVm
    {
    }

 public class TravelFeaturesVm : AvailableFeatureVm
    {
    }

 public class AvailableFeatureVm
    {
        public Guid FeatureId { get; set; }
        public bool HasFeature { get; set; }
        public string Name { get; set; }
    }


        private IList<AvailableFeature> FillAvailableFeatures(IEnumerable<AvailableFeatureVm> avaliableFeaturesVm)
        {
            List<AvailableFeature> availableFeatures = new List<AvailableFeature>();
            foreach (var f in avaliableFeaturesVm)
            {
                if (f.HasFeature)
                {
                                                    // nhibernate call to Load<>()
                    AvailableFeature availableFeature = featureService.LoadAvaliableFeatureById(f.FeatureId);
                    availableFeatures.Add(availableFeature);
                }
            }

            return availableFeatures;
        }

अब मैं आईएलस्ट को साधारण तथ्य के लिए वापस कर रहा हूं कि मैं इसे अपने डोमेन मॉडल में जोड़ दूंगा जिसके पास इस तरह की संपत्ति है:

public virtual IList<AvailableFeature> AvailableFeatures { get; set; }

ऊपर एक IList ही है क्योंकि यह वही है जो nhibernate के साथ उपयोग करने के लिए मानक है। अन्यथा मैं IEnumberable वापस लौट सकता था लेकिन निश्चित नहीं। फिर भी, मैं यह पता नहीं लगा सकता कि उपयोगकर्ता को 100% क्या चाहिए (यह वह जगह है जहाँ कंक्रीट वापस करने का एक फायदा है)।

संपादित करें २

मैं यह भी सोच रहा था कि क्या होगा अगर मैं अपने तरीके से संदर्भ देकर पास करना चाहता हूं?

private void FillAvailableFeatures(IEnumerable<AvailableFeatureVm> avaliableFeaturesVm, IList<AvailableFeature> toFill)
            {

                foreach (var f in avaliableFeaturesVm)
                {
                    if (f.HasFeature)
                    {
                                                        // nhibernate call to Load<>()
                        AvailableFeature availableFeature = featureService.LoadAvaliableFeatureById(f.FeatureId);
                        toFill.Add(availableFeature);
                    }
                }
            }

क्या मैं इसके साथ समस्याओं में भाग सकता हूं? चूंकि वे एक सरणी (जो एक निश्चित आकार है) में पास नहीं हो सकते थे? क्या यह एक ठोस सूची के लिए बेहतर होगा?

जवाबों:


156

यहां तीन प्रश्न हैं: मुझे औपचारिक पैरामीटर के लिए किस प्रकार का उपयोग करना चाहिए? मुझे स्थानीय चर के लिए क्या उपयोग करना चाहिए? और मुझे रिटर्न प्रकार के लिए क्या उपयोग करना चाहिए?

औपचारिक पैरामीटर:

यहां सिद्धांत आपको जरूरत से ज्यादा नहीं मांगता है । IEnumerable<T>संचार करता है "मुझे इस क्रम के तत्वों को शुरू से अंत तक प्राप्त करने की आवश्यकता है"। IList<T>संचार करता है "मुझे इस क्रम के तत्वों को मनमाने ढंग से प्राप्त करने और निर्धारित करने की आवश्यकता है"।List<T>संचार करता है "मुझे इस क्रम के तत्वों को मनमाने ढंग से प्राप्त करने और सेट करने की आवश्यकता है और मैं केवल सूचियों को स्वीकार करता हूं; मैं सरणियों को स्वीकार नहीं करता हूं।"

अपनी आवश्यकता से अधिक की माँग करके, आप (1) अपनी अनावश्यक माँगों को पूरा करने के लिए फोन करने वाले को अनावश्यक काम करते हैं, और (2) पाठक को झूठ का संचार करते हैं। जो आप उपयोग करने जा रहे हैं, उसके लिए ही पूछें। इस तरह से यदि कॉलर के पास कोई अनुक्रम है, तो उन्हें आपकी मांग को पूरा करने के लिए इस पर ToList को कॉल करने की आवश्यकता नहीं है।

स्थानीय चर:

जो चाहो प्रयोग करो। यह आपकी विधि है। आप केवल वही हैं जो विधि के आंतरिक कार्यान्वयन विवरणों को देखते हैं।

वापसी प्रकार:

पहले जैसा ही सिद्धांत, उलट। नंगे न्यूनतम की पेशकश करें जो आपके कॉलर की आवश्यकता है। यदि कॉल करने वाले को केवल अनुक्रम एन्यूमरेट करने की क्षमता की आवश्यकता होती है, तो केवल उन्हें ए IEnumerable<T>।


9
आप कैसे जानते हैं कि कॉलर को क्या चाहिए। उदाहरण के लिए, मैं अपने रिटर्न प्रकारों में से एक को IList <> में बदल रहा था, तो मैं अच्छी तरह से जानता हूं कि मैं शायद उन पर किसी भी तरह की गणना करने जा रहा हूं, बस एक IEnumberable को वापस करने देता है। तब मैंने अपने विचार (एमवीसी) में देखा और पाया कि मुझे वास्तव में गिनती विधि की आवश्यकता थी क्योंकि मुझे लूप का उपयोग करने की आवश्यकता थी। इसलिए अपने स्वयं के आवेदन में मैंने अनुमान लगाया कि मुझे वास्तव में क्या चाहिए, आप कैसे अनुमान लगाते हैं कि किसी और को आपकी आवश्यकता होगी या नहीं।
— चोबो

@ chobo2: अपने विशिष्ट उदाहरण में, LINQ Countहे (1) में काम करता है, तो आपके IEnumerableलिए एक है ICollection। बेशक, आप सिर्फ एक foreachलूप का उपयोग कर सकते हैं ।
— ब्रायन

6
@ chobo2: ठीक है, आप कैसे अनुमान लगाते हैं कि कॉलर को किन तरीकों की आवश्यकता होगी? ऐसा लगता है कि पहले हल करने के लिए समस्या। संभवत: किसी तरह आपके पास उन लोगों के लिए लिखने के तरीके जानने का एक तरीका है जो उन्हें कॉल करने जा रहे हैं। उन लोगों से पूछें कि वे वापस लौटने के तरीके क्या पसंद करेंगे। आपका प्रश्न मौलिक रूप से है "मुझे कैसे पता चलेगा कि सॉफ्टवेयर क्या लिखना है?" आपको पता चल जाता है कि आपके ग्राहक को किन समस्याओं का समाधान करना है, और कोड लिखना जो उनकी समस्याओं को हल करता है।
— एरिक लिपर्ट

1
@ ईरिक - आपको ICOLlection का उदाहरण शामिल करने के लिए औपचारिक मापदंडों के लिए अपने जवाब को अपडेट करना चाहिए जहां आपको केवल एक आइटम जोड़ने की आवश्यकता है। इसके अलावा आपके रिटर्न प्रकार के स्पष्टीकरण के साथ कुछ कहना चाहिए 'केवल कॉल करने वाले को प्रदर्शन करने की अनुमति देने की न्यूनतम न्यूनतम पेशकश करें'। यदि इसकी रीड ओनली लिस्ट में केवल IEnumerable, इत्यादि
— चार्ल्स लैम्बर्ट

4
@kvb: लगभग। अपने पहले परिदृश्य पर विचार करें। आप ऐसा करके एक एल्गोरिथम सुधार कर सकते हैं items as IList<T>और यदि आप गैर-अशक्त हैं, तो अपने बेहतर कोड का उपयोग करें। इस तरह से आप लाभ उठा सकते हैं यदि आप अभी भी ग्राहक के लचीलेपन की अनुमति देते हैं, तो वे क्या करते हैं?
— एरिक लिपिपर्ट

33

जेफरी रिक्टर द्वारा सीएलआर के माध्यम से सी # में मैंने जो सबसे व्यावहारिक कारण देखा है वह दिया गया था।

पैटर्न लेने के लिए है basest वर्ग या संभव इंटरफेस अपने तर्क के लिए और वापसी सबसे विशिष्ट वर्ग या संभव इंटरफेस अपनी वापसी प्रकार के लिए। यह आपके कॉलर्स को आपके तरीकों के प्रकारों को पारित करने में सबसे अधिक लचीलापन देता है और रिटर्न मानों को कास्ट / पुनः उपयोग करने के सबसे अधिक अवसर देता है।

उदाहरण के लिए, निम्न विधि

public void PrintTypes(IEnumerable items) 
{ 
    foreach(var item in items) 
        Console.WriteLine(item.GetType().FullName); 
}

किसी भी प्रकार में पारित करने के लिए विधि को अनुमति देता है जिसे एक गणनीय के लिए डाला जा सकता है । यदि आप अधिक विशिष्ट थे

public void PrintTypes(List items)

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

जब वापसी के प्रकारों के बारे में बात की जाती है, तो आप जितने विशिष्ट होते हैं, उतने ही लचीले कॉलर इसके साथ हो सकते हैं।

public List<string> GetNames()

आप नामों को पुनरावृत्त करने के लिए इस वापसी प्रकार का उपयोग कर सकते हैं

foreach(var name in GetNames())

या आप सीधे संग्रह में अनुक्रमित कर सकते हैं

Console.WriteLine(GetNames()[0])

जबकि, यदि आप एक कम विशिष्ट प्रकार वापस पा रहे थे

public IEnumerable GetNames()

पहला मान प्राप्त करने के लिए आपको वापसी प्रकार की मालिश करनी होगी

Console.WriteLine(GetNames().OfType<string>().First());

10
ध्यान दें कि यह सलाह रिटर्न प्रकारों के लिए सिफारिश में एरिक लिपर्ट के जवाब का खंडन करती है। जेफरी रिक्टर का दृष्टिकोण विधि के उपभोक्ताओं को उनकी पसंद की लौटी हुई वस्तु का उपयोग करने के लिए सबसे अधिक लचीलापन देता है, जबकि एरिक विधि के अनुरक्षकों को विधि की सार्वजनिक सतह को संशोधित किए बिना कार्यान्वयन को बदलने के लिए सबसे अधिक लचीलापन देता है। मैं आंतरिक कोड के लिए जेफरी की सलाह का पालन करता हूं, लेकिन एक सार्वजनिक पुस्तकालय के लिए, मैं शायद एरिक का अनुसरण करने के लिए अधिक इच्छुक हूं।
— फोग

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

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

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

1
+1 ट्रिविया: यह उत्तर पोस्टेल के कानून का एक अच्छा, CLR- विशिष्ट उदाहरण है । :)
— दान जे

13

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

यदि आप अपनी संपत्ति को एक List<T>या एक के रूप में IList<T>तब भी उजागर करते हैं जब आप चाहते हैं कि आपके उपभोक्ता के पास संग्रह के माध्यम से पुनरावृति करने की क्षमता हो। तब वे इस तथ्य पर निर्भर हो सकते हैं कि वे सूची को संशोधित कर सकते हैं। फिर बाद में यदि आप एक से वास्तविक डेटा की दुकान में परिवर्तित करने का फैसला List<T>एक के लिए Dictionary<T,U>संपत्ति के लिए वास्तविक मूल्य के रूप में और चाबी शब्दकोश बेनकाब (मैं वास्तव में इस से पहले क्या करना पड़ा है)। फिर जो उपभोक्ता यह उम्मीद करने आए हैं कि आपके वर्ग के अंदर उनके परिवर्तन परिलक्षित होंगे, अब वह क्षमता नहीं होगी। यह एक बड़ी समस्या है! यदि आप List<T>एक के रूप में उजागर करते हैं तो आप IEnumerable<T>आराम से अनुमान लगा सकते हैं कि आपके संग्रह को बाहरी रूप से संशोधित नहीं किया जा रहा है। यह List<T>उपरोक्त इंटरफेस में से किसी के रूप में उजागर करने की शक्तियों में से एक है।

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

इस से यह इस प्रकार है कि आपकी विधि कार्यान्वयन आपके स्थानीय चर का प्रतिनिधित्व कर सकता है, हालांकि आप चाहें। कार्यान्वयन का विवरण सामने नहीं आया है। अपने कोड को कॉल करने वाले लोगों को प्रभावित किए बिना अपने कोड को बेहतर तरीके से बदलने के लिए आपको छोड़कर।

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


9

संक्षिप्त जवाब:

आप इंटरफ़ेस को पास करते हैं ताकि आपके द्वारा उपयोग किए जाने वाले उस इंटरफ़ेस का कोई ठोस क्रियान्वयन न हो, आपका कोड इसका समर्थन करेगा।

यदि आप सूची के एक ठोस कार्यान्वयन का उपयोग करते हैं, तो उसी सूची का एक और कार्यान्वयन आपके कोड द्वारा समर्थित नहीं होगा।

विरासत और बहुरूपता पर थोड़ा पढ़ें ।


8

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

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

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


3

विधि के अंदर, आपको varइसके बजाय IListया का उपयोग करना चाहिए List। जब आपके डेटा स्रोत के बजाय एक विधि से आना बदल जाता है, तो आपकी onlySomeIntsविधि बच जाएगी।

मापदंडों के IListबजाय उपयोग करने का कारण है List, क्योंकि कई चीजें लागू होती हैं IList(सूची और [], दो उदाहरणों के रूप में), लेकिन केवल एक चीज लागू होती है List। यह इंटरफ़ेस के कोड के लिए अधिक लचीला है।

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


13
यह कहते हुए कि उसे "var" का उपयोग करना चाहिए पूरी तरह से गलत है। इससे कोई फर्क नहीं पड़ता कि वह वहां क्या उपयोग करता है - यह एक शैली मुद्दा है। यह विधि के हस्ताक्षर को प्रभावित नहीं करता है, और संकलन समय पर पत्थर में सेट किया गया है। आपको इलिस्ट फू = नई सूची जैसे अपने स्थानीय को घोषित करने के बारे में भ्रम की स्थिति को खत्म करने में उसकी मदद करने में मदद करनी चाहिए - यह वह जगह है जहां उसका भ्रम स्पष्ट रूप से निहित है।
— x0n

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

यह सच है, "यूज वर्जन" का बिंदु अधिक सुझाव था कि वह इस पद्धति के बारे में चिंता न करें और उपभोक्ताओं को कैसे दिखता है, इस पर अधिक ध्यान दें।
— ब्रायन बोएचर

मैं @ x0n से सहमत हूं: var का उपयोग बहुत अधिक है और यह कुछ भी स्पष्ट करने में मदद नहीं करेगा।
— वह चक गय

1

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

इंटरफेस का उपयोग करने का दूसरा सामान्य कारण किसी वस्तु के उपयोगकर्ता के लिए आवश्यक न्यूनतम ज्ञान को उजागर करना है।

उस पर (विवादित) मामले पर विचार करें जहां मेरे पास एक डेटा ऑब्जेक्ट है जो IList को लागू करता है।

public class MyDataObject : IList<int>
{
    public void Method1()
    {
       ...
    }
    // etc
}

ऊपर दिए गए आपके कार्य केवल एक सूची पर पुनरावृति करने में सक्षम होने के बारे में परवाह करते हैं आदर्श रूप से उन्हें यह जानने की जरूरत नहीं है कि उस सूची को कौन लागू करता है या वे इसे कैसे लागू करते हैं।

आपके उदाहरण में, IEnumerable एक बेहतर विकल्प है जैसा आपने सोचा था।


1

हमेशा अपने कोड के बीच निर्भरता को कम करना एक अच्छा विचार है जितना संभव हो।

इसे ध्यान में रखते हुए, यह सबसे अधिक समझ में आता है कि बाहरी निर्भरता की कम से कम संख्या के साथ प्रकारों को पास करना और उसी को वापस करना। हालाँकि, यह आपके तरीकों की दृश्यता और उनके हस्ताक्षरों के आधार पर भिन्न हो सकता है।

यदि आपके तरीके इंटरफ़ेस का हिस्सा बनते हैं, तो तरीकों को उस इंटरफ़ेस के लिए उपलब्ध प्रकारों का उपयोग करके परिभाषित करना होगा। कंक्रीट प्रकार संभवतः इंटरफेस के लिए उपलब्ध नहीं होंगे, इसलिए उन्हें गैर-कंक्रीट प्रकार वापस करना होगा। आप ऐसा करना चाहते हैं यदि आप एक रूपरेखा बना रहे हैं, उदाहरण के लिए।

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


1

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

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


0

इस .NET 4.5+ दुनिया में मेरा जवाब है ।

उपयोग IList <टी> और IReadonlyList <टी> ,
              के बजाय सूची <टी> , क्योंकि ReadonlyList <टी> मौजूद नहीं है।

IList <T> IReadonlyList <T> के अनुरूप है

  • न्यूनतम एक्सपोज़र (प्रॉपर्टी) या आवश्यकता (पैरामीटर) के लिए IEnumerable <T> का उपयोग करें यदि फोरचैट इसका उपयोग करने का एकमात्र तरीका है।
  • IReadonlyList का उपयोग करें <T> यदि आपको भी गणना और [] अनुक्रमणिका का उपयोग / खुलासा करने की आवश्यकता है ।
  • यदि आप कॉलर को तत्वों को जोड़ने / अपडेट / हटाने की अनुमति देते हैं तो IList <T> का उपयोग करें

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

एक उदाहरण वर्ग:

// manipulate the list within the class
private List<int> _numbers;

// callers can add/update/remove elements, but cannot reassign a new list to this property
public IList<int> Numbers { get { return _numbers; } }

// callers can use: .Count and .ReadonlyNumbers[idx], but cannot add/update/remove elements
public IReadOnlyList<int> ReadonlyNumbers { get { return _numbers; } }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.