2011-02-04 16 views
9

यदि मैं कक्षा की संपत्ति के रूप में IEnumerable<T> का पर्दाफाश करता हूं, तो क्या कोई संभावना है कि इसे कक्षा के उपयोगकर्ताओं द्वारा उत्परिवर्तित किया जा सके, और यदि ऐसा है तो उत्परिवर्तन के खिलाफ सुरक्षा का सबसे अच्छा तरीका क्या है, जबकि उजागर संपत्ति के प्रकार IEnumerable<T> ?क्या संपत्ति में एक आईनेमरेबल का पर्दाफाश करना सुरक्षित है?

+0

कुछ चेतावनियां जबकि संपत्ति के रूप में संग्रह का उपयोग कर रहे हैं, MSDN https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/guidelines-for-collections से इस डिजाइन दिशानिर्देश लिंक की जाँच करें –

उत्तर

14

यह आपके द्वारा लौटने पर निर्भर करता है। यदि आप एक म्यूटेबल List<string> लौटते हैं (कहें) तो ग्राहक वास्तव में इसे List<string> पर वापस ला सकता है और इसे बदल सकता है।

आप अपने डेटा की रक्षा कैसे करते हैं इस पर निर्भर करता है कि आपको किसके साथ शुरुआत करना है। ReadOnlyCollection<T> एक अच्छा रैपर वर्ग है, मानते हुए कि आपको IList<T> से शुरू करने के लिए मिला है।

public IEnumerable<string> Names 
{ 
    get { return names.Select(x => x); } 
} 

जो प्रभावी रूप से एक iterator में संग्रह लपेटता:

अपने ग्राहकों IList<T> या ICollection<T> को लागू करने वापसी मान से लाभ नहीं होगा, तो आप हमेशा की तरह कुछ कर सकता है। (स्रोत को छिपाने के लिए LINQ का उपयोग करने के कई अलग-अलग तरीके हैं ... हालांकि यह दस्तावेज नहीं है कि कौन से ऑपरेटर स्रोत को छुपाते हैं और जो नहीं करते हैं। उदाहरण के लिए Skip(0) माइक्रोसॉफ्ट कार्यान्वयन में स्रोत को छुपाता है, लेकिन यह नहीं है ऐसा करने के लिए प्रलेखित।)

Select निश्चित रूप से हालांकि स्रोत को छुपाएं।

+1

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

1

संग्रह को मूल प्रकार में वापस लाया जा सकता है और यदि यह उत्परिवर्तनीय है तो इसे फिर से परिवर्तित किया जा सकता है।

मूल रूप से उत्परिवर्तित होने की संभावना से बचने का एक तरीका है सूची सूची की प्रतिलिपि कर रहा है।

+0

एक क्लोन बनाना एक संभावित तरीका है, है, लेकिन क्या वास्तव में यह "सबसे अच्छा तरीका" है? शायद कभी-कभी यह होता है, लेकिन कभी-कभी नहीं। –

+0

एक प्रतिलिपि बड़ी संग्रह के लिए महंगा है। जब तक मुझे वास्तव में एक प्रतिलिपि के अर्थशास्त्र की आवश्यकता नहीं होती है, मैं जॉनस्केट जैसे रैपर पसंद करता हूं। – CodesInChaos

+0

@ एएल, @CodeInChaos - उचित अंक ... उत्तर संशोधित। – Oded

2

उपयोगकर्ता संग्रह कक्षा में वापस लौटने में सक्षम हो सकता है, इसलिए खुलासा करें।

collection.Select(x => x) 

और इस मिल जाएगा एक नया IEnumerable बनाया कि संग्रह

+0

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

0

मैं एक iterator में एक IEnumerable लपेटकर अंतर्निहित कनेक्शन के साथ monkeying से प्राप्तकर्ताओं को रोकने के लिए सुझाव है कि नहीं होगा में ढाला नहीं जा सकता है।

public struct WrappedEnumerable<T> : IEnumerable<T> 
{ 
    IEnumerable<T> _dataSource; 
    public WrappedEnumerable(IEnumerable<T> dataSource) 
    { 
     _dataSource = dataSource; 
    } 
    public IEnumerator<T> GetEnumerator() 
    { 
     return _dataSource.GetEnumerator(); 
    } 
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return ((System.Collections.IEnumerable)_dataSource).GetEnumerator(); 
    } 
} 

संपत्तियों की वापसी प्रकार IEnumerable<T>, WrappedEnumerable<T>IEnumerable<T> करने से प्रकार बलात्कार संरचना बॉक्स और व्यवहार और प्रदर्शन मैच होगा एक वर्ग के उन लोगों के है: मेरा झुकाव की तरह एक आवरण कुछ का उपयोग किया जाएगा । यदि, हालांकि, गुणों को लौटने वाले प्रकार WrappedEnumerable<T> के रूप में परिभाषित किया गया था, तो उन मामलों में एक मुक्केबाजी चरण को सहेजना संभव होगा जहां कॉलिंग कोड या तो WrappedEnumerable<T> की संपत्ति पर लौटाएगा (संभवतः var myKeys = myCollection.Keys; जैसे कुछ के परिणामस्वरूप) या बस "foreach" लूप में सीधे संपत्ति का उपयोग करता है। ध्यान दें कि GetEnumerator() द्वारा लौटाए गए गणक एक संरचना होगी, जिसे अभी भी किसी भी मामले में बॉक्स किया जाना होगा।

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

भी ध्यान दें कि यह कुछ मामलों में किसी भी मुक्केबाजी के लिए आवश्यकता को खत्म करने और सी # और vb.net foreach पाश में बतख टाइपिंग अनुकूलन शोषण करता है, तो एक एक प्रकार की तरह इस्तेमाल किया संभव हो सकता है:

public struct FancyWrappedEnumerable<TItems,TEnumerator,TDataSource> : IEnumerable<TItems> where TEnumerator : IEnumerator<TItems> 
{ 
    TDataSource _dataSource; 
    Func<TDataSource,TEnumerator> _convertor; 
    public FancyWrappedEnumerable(TDataSource dataSource, Func<TDataSource, TEnumerator> convertor) 
    { 
     _dataSource = dataSource; 
     _convertor = convertor; 
    } 
    public TEnumerator GetEnumerator() 
    { 
     return _convertor(_dataSource); 
    } 
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return _convertor(_dataSource); 
    } 
} 

convertor प्रतिनिधि एक स्थिर प्रतिनिधि हो सकता है, और इस प्रकार रन-टाइम (कक्षा प्रारंभिकरण के बाहर) पर किसी भी ढेर-वस्तु निर्माण की आवश्यकता नहीं होती है। इस दृष्टिकोण का उपयोग करते हुए, यदि कोई List<int> से एक गणक वापस करना चाहता था, तो संपत्ति वापसी प्रकार FancyWrappedEnumerable<int, List<int>.Enumerator, List> होगा। शायद उचित अगर कॉलर ने सीधे foreach लूप में या var घोषणा में सीधे संपत्ति का उपयोग किया, लेकिन बदले में अगर कॉलर इस प्रकार के भंडारण स्थान को ऐसे तरीके से घोषित करना चाहता था जो var का उपयोग नहीं कर सके।

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