2012-06-26 9 views
13

प्रसंग:क्या .NET डिज़ाइन दिशानिर्देश INumerable <T> पर सूची <T> लौटने का सुझाव देते हैं?

: मैं एक ईमेल अपने सहयोगियों के लिए उन्हें यह बताने Enumerable.Empty<T>() के बारे में return new List<T>(); की तरह कुछ कर रही बिना मैं एक उत्तर कह नकारात्मक पक्ष यह है कि यह एक विशेष प्रकार का खुलासा नहीं करता है कि मिल गया खाली संग्रह वापस जाने के लिए एक तरह से के रूप में भेजा

यह एक छोटा मुद्दा प्रस्तुत करता है। अपने रिटर्न प्रकार * के बारे में जितना संभव हो उतना सटीक होना हमेशा अच्छा होता है (इसलिए यदि आप एक सूची <> वापस कर रहे हैं, तो इसे अपना रिटर्न टाइप करें); ऐसा इसलिए है क्योंकि सूचियों और Arrays जैसी चीजें अतिरिक्त विधियां हैं जो उपयोगी हैं। इसके अलावा कॉलिंग विधि से संग्रह का उपयोग करते समय प्रदर्शन विचारों को बनाने में भी उपयोगी हो सकता है।

दुर्भाग्य से नीचे की चाल आपको एक आईनेमरेबल लौटने के लिए मजबूर करती है, जो जितना संभव हो उतना गैर-विशिष्ट है, है ना? :(

* यह नेट डिजाइन दिशानिर्देश से वास्तव में है। दिशा निर्देशों में कहा कारणों ही के रूप में मैं यहाँ यह उल्लेख कर रहा हूँ, मेरा मानना ​​है कि कर रहे हैं।

इस की पूरी विपरीत लग रहा था क्या मुझे पता चला था, और के रूप में मैं हो सकता है की कोशिश, मैं डिजाइन के दिशा निर्देशों में इस सटीक सलाह नहीं पा सके मैं इस तरह एक छोटा सा टुकड़ा मिला:।

बहुत से वापसी Collection<T> या ReadOnlyConnection<T> का एक उपवर्ग DO आमतौर पर प्रयुक्त विधियों और गुणों।

कोड स्निपेट के बाद, लेकिन कोई और औचित्य नहीं है।


तो ही कहा जा रहा है, यह एक वास्तविक और स्वीकार किए जाते हैं दिशानिर्देश (जिस तरह से यह पहला ब्लॉक कोट में वर्णित किया गया था) क्या है? या क्या इसका गलत व्याख्या किया गया है? अन्य सभी SO प्रश्न जो मुझे मिल सकते हैं, जवाब IEnumerable<T> को रिटर्न प्रकार के रूप में पसंद करते हैं। हो सकता है कि मूल .NET दिशानिर्देश अभी पुराना हो?

या शायद यह इतना स्पष्ट कट नहीं है? क्या विचार करने के लिए कुछ ट्रेडऑफ हैं? एक और विशिष्ट प्रकार वापस करने के लिए एक अच्छा विचार कब होगा? क्या कभी किसी ठोस जेनेरिक प्रकार को वापस करने की सिफारिश की जाती है, या केवल IList<T> और ReadOnlyCollection<T> जैसे अधिक विशिष्ट इंटरफ़ेस को वापस करने के लिए?

+4

मेरे पास इसका कोई संदर्भ नहीं है, लेकिन मैंने हमेशा यह पढ़ा है कि सबसे सामान्य प्रकार को संभवतः वापस करने के लिए सबसे अच्छा है। तो 'केवल पढ़ने के लिए' IENumerable 'संपादित करने के लिए, 'संपादन योग्य संग्रह के लिए' ICollection ' और 'IList ' यदि आपको अनुक्रमित संपादन योग्य संग्रह की आवश्यकता है। – jrummell

+7

मैं व्यक्तिगत रूप से हमेशा * कम से कम * विशिष्ट प्रकार को वापस करने की कोशिश करता हूं। मेरी विधियां जो कई आइटम्स को 'IENumerable ' पर डिफ़ॉल्ट रूप से लौटाती हैं, जब तक कि अन्यथा करने के लिए बहुत अच्छा कारण न हो (और वहां बहुत ही कम है।) उन मामलों में जहां मैं यह स्पष्ट करना चाहता हूं कि संग्रह एक अनुक्रमणीय सूची है, मैं ' ReadOnlyCollection '। आम तौर पर, आमतौर पर उपभोक्ताओं को एक परिवर्तनीय सूची लौटने का कोई कारण नहीं होता है। .NET दिशानिर्देशों को यहां पुराना हो सकता है। – dlev

+1

क्या आपके पास उद्धृत .NET डिज़ाइन दिशानिर्देशों का लिंक है? मुझे अनुमान है कि कहीं यहां दफनाया गया है: http://msdn.microsoft.com/en-us/library/ms229042 – jrummell

उत्तर

12

दोनों शैलियों के लिए कारण हैं:

  1. विशिष्ट बनें: आप कॉल है कि आप हमेशा इस प्रकार वापस आ जाएगी करने के लिए एक गारंटी कर रहे हैं। यहां तक ​​कि जब आपका कार्यान्वयन बदलता है। क्या आप वादा रख सकते हैं? यदि हां, कॉलर्स को लाभ देने के लिए विशिष्ट हो। अधिक व्युत्पन्न प्रकारों में अधिक सुविधाएं हैं।
  2. हो जेनेरिक: यदि आप प्रश्न में विधि या संपत्ति के अंतर्निहित कार्यान्वयन बदलने की संभावना हैं, तो आप एक List<T> वादा नहीं कर सकता। शायद आप IList<T> या एक कस्टम संग्रह वर्ग (जिसे आप बाद में बदल सकते हैं) का वादा कर सकते हैं।

.NET ढांचा बीसीएल या तो सरणी या कस्टम संग्रह कक्षाओं के साथ जाता है। उन्हें 100% स्थिर एपीआई प्रदान करने की आवश्यकता है ताकि उन्हें सावधान रहना पड़े।

सामान्य सॉफ़्टवेयर प्रोजेक्ट्स में आप कॉलर को बदल सकते हैं (जो .NET फ्रेमवर्क लोग नहीं कर सकते हैं), ताकि आप अधिक उदार हो सकें। यदि आप बहुत अधिक वादा करते हैं, और एक वर्ष बाद इसे बदलने की जरूरत है, तो आप ऐसा कर सकते हैं (कुछ प्रयासों के साथ)।

केवल एक चीज है जो हमेशा गलत होती है: यह कहकर कि हमेशा करें (1) या (2)। हमेशा हमेशा गलत है।

यहाँ एक मामले के लिए एक उदाहरण है जहां विशिष्टता स्पष्ट रूप से सही विकल्प है:

public static T[] Slice<T>(this T[] list, int start, int count) 
    { 
     var result = new T[count]; 
     Array.Copy(list, start, result, 0, count); 
     return result; 
    } 

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

दूसरी तरफ, कुछ लगातार स्टोर से सभी उपयोगकर्ताओं को वापस करने का एक तरीका आंतरिक रूप से बहुत बदल सकता है। डेटा उपलब्ध स्मृति से भी बड़ा हो सकता है, जिसके लिए स्ट्रीमिंग की आवश्यकता होती है। हमें शायद IEnumerable<User> चुनना चाहिए।

+0

हा, यह उत्तर मेरे मुकाबले ज्यादा संक्षिप्त है। अच्छी तरह से कहा गया। –

0

आईएमओ यह याद रखना महत्वपूर्ण है कि List<T> और IEnumerable<T> में विभिन्न अर्थशास्त्र हैं।

रिटर्निंग IEnumerable<T> सिर्फ कॉलर को कुछ ऐसा अनुक्रम देता है जिसे समझा जा सकता है (और संभवतः संग्रह में बदल दिया जा सकता है)। हालांकि, इस बात की कोई गारंटी नहीं है कि अनुक्रम को पूरा किया गया है। तो IEnumerable<T> लौटाकर स्थगित निष्पादन का समर्थन करता है। इसके अलावा, यह निश्चित रूप से "केवल पढ़ने" है।

List<T> लौटने का अर्थ यहां एक संग्रह है। जब विधि वापस आती है तो सभी काम किए जाते हैं। इसके अलावा, List<T> का इंटरफ़ेस कॉलर को तुरंत संग्रह को संशोधित करने देता है।

+0

IList आम तौर पर सूची (उदाहरण के लिए FxCop) पर सार्वजनिक एपीआई में प्राथमिकता दी जाती है। और IList का उपयोग उचित रूप से किया जा सकता है एक पठनीय सूची लौटाएं। मैं केवल आईनेमेरेबल का उपयोग करता हूं अगर मैं कॉलर को इंगित करना चाहता हूं कि एपीआई स्थगित निष्पादन का समर्थन कर सकता है। – Joe

+0

सी # भाषा के उपयोगकर्ताओं को यह नहीं मानना ​​चाहिए कि IENumerable लौटने वाला कुछ भी आलसी (या नहीं) होगा,

दस्तावेज़ यह महत्वपूर्ण या संदिग्ध होने पर इंगित करने का एक बेहतर तरीका है। –

+0

मैंने यह नहीं कहा कि उन्हें कुछ भी मानना ​​चाहिए। मैंने कहा कि IENumerable वापस लौटने का समर्थन करता है। एक सूची लौटाना नहीं है। –

4

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

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

एक अलग लेकिन मेरी राय में समान रूप से मान्य वैकल्पिक दर्शन यह होगा कि अधिक सामान्य प्रकार लौटने से आपकी लाइब्रेरी कम उपयोगी हो जाती है, और इसलिए आपको विशिष्ट प्रकारों को वापस करना चाहिए। उदाहरण के लिए आक्रामक रूप से IEnumerable<T> लौटने से परिदृश्य सामने आएगा जहां आपकी लाइब्रेरी के अंतिम उपयोगकर्ता लगातार ToArray(), ToList() आदि पर कॉल कर रहे हैं। मुझे विश्वास है कि यह आपका मुख्य कार्यकर्ता है जब वह लिखा था कि "सूचियों और Arrays जैसी चीजें हैं अतिरिक्त विधियां जो उपयोगी हैं। "

मैंने कभी-कभी "आपके द्वारा ऑफ़र किए जाने वाले विशिष्ट में विशिष्ट बनें, लेकिन जो भी आप स्वीकार करते हैं उसमें सामान्य" के आधार पर शब्दों में वकालत करने वाले बाद के दृष्टिकोण को सुना है। दूसरे शब्दों में, जेनेरिक पैरामीटर लें लेकिन विशिष्ट वापसी मान प्रदान करें।चाहे आप इस सिद्धांत से सहमत हों या नहीं, कम से कम इसके पीछे कारण देखना आसान है।

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

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

तो यह हमेशा एक व्यापार-बंद होने जा रहा है, और सबसे अच्छा दिशानिर्देश मुझे लगता है कि आप हमेशा अपने विकल्पों पर विचार करना और प्रश्न के मामले में सबसे समझदार व्यक्ति चुनने के लिए अपने फैसले का उपयोग करना है।

2

IEnumerable (या कम से कम IList) के बजाय सूची रिटर्निंग अनिवार्य रूप से उस प्रकार वापस जाने के लिए की आवश्यकता होगी, में आप Liskov Sustitution Principle

रिटर्निंग "सूची" ताले का उल्लंघन करता है, और आप एक संभावित रूप से अधिक करने के लिए विधि के आंतरिक पुनर्रचना करने से रोकता है कुशल कार्यान्वयन (आपने सूची वापस करने का वादा किया था, लेकिन अब आप "उपज" का उपयोग करना चाहते हैं - ओह, बाहरी कोड-मंथन के बिना इसे नहीं कर सकते हैं)।

(अधिकांश?) मामलों में, इस तरह के तरीकों की मुख्य आवश्यकता परिणामों पर फिर से चलना और कुछ करना है ... IENumerable इन उपयोगों के लिए बिल्कुल उपयुक्त है।

यदि उपयोगकर्ता को एक म्यूटेबल सेट होना आवश्यक है, तो यह "टोलिस्ट()" या अन्य अंत में IENumerable पर अन्य एक्सटेंशन का उपयोग करके छोटे से पूरा किया जाता है।

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

+0

शायद "उल्लंघन" एक शब्द बहुत मजबूत है, लेकिन मेरा मुद्दा यह है कि यदि आप कई आवश्यकताओं के साथ एक विशिष्ट ठोस प्रकार वापस करते हैं, तो इसे बाद में इसे बदलना कठिन होता है। –

+0

कई मामलों में, एक कॉलर कई बार संग्रह पर गिनती और/या पुनरावृत्ति प्राप्त करना चाहता है। इस मामले में एक IList रिटर्न प्रकार अधिक उपयोगी है (कॉलर को अनिवार्य रूप से ToList() आदि को कॉल करने से बचाता है)। किसी भी मामले में, पसंद के पास लिस्कोव प्रतिस्थापन सिद्धांत के साथ कुछ लेना देना नहीं है। – Joe

+0

@joe विधि को कार्यान्वित करने के परिप्रेक्ष्य से, यह उपभोक्ता के परिप्रेक्ष्य से एलएसपी से प्रभावित होता है, आप वास्तव में यह आईएसपी का उल्लंघन का दावा कर सकते हैं, लेकिन किसी भी मामले में एपीआई संभवतः यह बता रहा है कि यह क्या लौट रहा है। कॉलर इसके साथ क्या कर सकता है, उन पर निर्भर करता है, इस तरह के उद्देश्य के लिए एक आईनेमरेबल को संग्रह में बदलने के लिए तुच्छ है, लेकिन यह कॉलर पर जो कुछ भी हो सकता है उसे हल करने के लिए कॉलर पर रखता है और आपके कार्यान्वयन को बदलने के लिए आपको छोड़ देता है यदि आपको अधिक कुशल या उचित कार्यान्वयन मिलता है। हालांकि, यह एक शैली पसंद है। –

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