2010-02-19 4 views
6

अगर मैं निम्नलिखित वर्ग के सदस्य हैं:एक निजी संग्रह पर पुनरावृत्ति की अनुमति कैसे दें लेकिन संशोधन नहीं?

private List<object> obs; 

और मैं क्लास 'इंटरफेस के हिस्से के रूप में इस सूची की ट्रेवर्सल अनुमति देना चाहते हैं, मैं इसे कैसे करना होगा?

इसे सार्वजनिक बनाना काम नहीं करेगा क्योंकि मैं सूची को सीधे संशोधित करने की अनुमति नहीं देना चाहता हूं।

उत्तर

12

आप एक IEnumerable<T> के रूप में यह पर्दाफाश होगा, लेकिन बस उसे सीधे वापस नहीं:

public IEnumerable<object> Objects { get { return obs.Select(o => o); } } 

के बाद से है, जिसे आपने केवल सूची के ट्रेवर्सल चाहता था, यह सब आप की जरूरत है।

एक एक IEnumerable<T> के रूप में सीधे List<object> वापसी करने के लिए परीक्षा हो सकती है, लेकिन यह है कि, सही नहीं होगा और क्योंकि एक को आसानी से रन टाइम पर IEnumerable<T> निरीक्षण का निर्धारण यह एक List<T> है और इस तरह के लिए यह डाली और सामग्री उत्परिवर्तित सकता है।

हालांकि, return obs.Select(o => o); का उपयोग करके आप List<object> पर एक पुनरावर्तक लौटते हैं, List<object> के प्रत्यक्ष संदर्भ के लिए नहीं।

कुछ सोच सकते हैं कि यह सी # भाषा विशिष्टता की धारा 7.15.2.5 के अनुसार "अपमानजनक अभिव्यक्ति" के रूप में योग्यता प्राप्त करता है। हालांकि, Eric Lippert goes into detail as to why this projection isn't optimized away

इसके अलावा, लोग सुझाव दे रहे हैं कि AsEnumerable extension method का उपयोग करें। यह गलत है, क्योंकि मूल सूची की संदर्भ पहचान बनाए रखा जाता है।

AsEnumerable<TSource>(IEnumerable<TSource>) विधि अन्य एक प्रकार है कि IEnumerable<T> ही IEnumerable<T> लागू करता है से स्रोत का संकलन समय प्रकार बदलने के लिए की तुलना में कोई प्रभाव नहीं है: दस्तावेज की टिप्पणियां अनुभाग से।

दूसरे शब्दों में, सब यह होता है IEnumerable<T>, जो referencial अखंडता की रक्षा में मदद नहीं करता करने के लिए स्रोत पैरामीटर डाली है, मूल संदर्भ दिया जाता है और List<T> वापस करने के लिए डाली जा सकती है और इस सूची में उत्परिवर्तित लिए इस्तेमाल किया जा।

+2

ध्यान दें कि अगर आप अपने कोड में दिखाई देते हैं तो हम कभी भी * स्पष्ट * कॉल को ऑप्टिमाइज़ नहीं करेंगे। विधि कॉल में क्वेरी अभिव्यक्ति को परिवर्तित करते समय हम चयन करने के लिए निहित कॉल को ऑप्टिमाइज़ करेंगे। यदि आप कहते हैं "एक्स में वाई से जहां बी एक्स का चयन करें" कोई कॉल नहीं है, बस एक कहां है। लेकिन अगर आप कहते हैं "x में y select x" से हम "y" उत्पन्न नहीं करते हैं, तो हम परिणाम की अपरिवर्तनीयता सुनिश्चित करने के लिए एक चुनिंदा कॉल उत्पन्न करते हैं। –

0

क्या आपने System.Collections.ReadOnlyCollectionBase से कक्षा प्राप्त करने पर विचार किया है?

11

आप ReadOnlyCollection का उपयोग कर सकते हैं या List की एक प्रति बना सकते हैं और इसे कॉपी कर सकते हैं (कॉपी ऑपरेशन के प्रदर्शन दंड पर विचार करते हुए)। आप List<T>.AsReadOnly का भी उपयोग कर सकते हैं।

+0

उत्तर अधूरा है। कृपया कोड –

1

बेनकाब एक ReadOnlyCollection<T>

+0

कैसे? खराब उत्तर –

+1

प्रश्नकर्ता को थोड़ा शिकार करने के लिए बिल्कुल समस्या नहीं है। Google पर पहला परिणाम यह स्पष्ट करता है कि 'ReadOnlyCollection 'का खुलासा कैसे करें। – user7116

+0

छः पत्रिकाएं आप स्पष्ट रूप से साइट के बिंदु को याद करते हैं। –

2

आप दो तरह से कर सकते हैं:

  1. या तो एक केवल पढ़ने के लिए संग्रह में सूची परिवर्तित द्वारा:

    new System.Collections.ObjectModel.ReadOnlyCollection<object>(this.obs) 
    
  2. या के एक IEnumerable वापस लौट कर आइटम:

    this.obs.AsEnumerable() 
    
2
करने के लिए अपने इंटरफेस के लिए निम्न विधि हस्ताक्षर जोड़ने

public IEnumerable<object> TraverseTheList() 
{ 

    foreach(object item in obj) 
    { 
     yield return item; 
    } 


} 

कि आप निम्न करने की अनुमति देगा:

foreach(object item in Something.TraverseTheList()) 
{ 
// do something to the item 
} 

उपज वापसी आपके लिए एक गणक बनाने के लिए कंपाइलर को बताती है।

+0

एक अलग कोण; अति उत्कृष्ट। –

3

यह पहले से ही कहा जा चुका है, लेकिन मुझे कोई जवाब सुपरकलर के रूप में नहीं दिख रहा है।

सबसे आसान तरीका है बस एक ReadOnlyCollection वापस जाने के लिए है

private List<object> objs; 

public ReadOnlyCollection<object> Objs { 
    get { 
     return objs.AsReadOnly(); 
    } 
} 

इस के साथ दोष यह है, यह है कि आप बाद में अपने कार्यान्वयन को बदलना चाहते हैं, तो कुछ कॉल करने को पहले से ही इस तथ्य पर निर्भर है, हो सकता है कि संग्रह यादृच्छिक पहुंच प्रदान करता है। तो एक सुरक्षित परिभाषा सिर्फ बेनकाब करने के लिए एक IEnumerable

public IEnumerable<object> Objs { 
    get { 
     return objs.AsReadOnly(); 
    } 
} 

ध्यान दें कि आप इस कोड को संकलित करने के लिए AsReadOnly() कॉल करने के लिए की जरूरत नहीं है किया जाएगा। लेकिन अगर आप नहीं करते हैं, तो कॉलर ने मेरी वापसी सूची को वापस सूची में डाला और अपनी सूची संशोधित की।

// Bad caller code 
var objs = YourClass.Objs; 
var list = objs as List<object>; 
list.Add(new object); // They have just modified your list. 

ही संभावित समस्या भी इस समाधान

public IEnumerable<object> Objs { 
    get { 
     return objs.AsEnumerable(); 
    } 
} 

के साथ मौजूद है तो मैं निश्चित रूप से सुझाव है कि आप आप सूची में AsReadOnly() कहते हैं, और है कि मूल्य वापस है।

+0

सरल + सुरक्षित का महान संयोजन। –

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