2015-03-26 6 views
5

सी # (कम से कम, जबकि ImmutableArray बीटा में है) में उत्पादन कोड के लिए एक सरणी के लिए अपरिवर्तनीय विकल्प क्या हैं?सी # में एक सरणी के लिए अपरिवर्तनीय विकल्प क्या हैं?

+2

आप किस उद्देश्य को प्राप्त करने का प्रयास कर रहे हैं? हो सकता है कि किसी सरणी के बजाय 'IENumerable' गुजरना आपकी समस्या का समाधान कर सके? –

+0

मुझे लगता है कि एरे गिनती प्राप्त करने और सभी सामग्री को एक बार में पढ़ने में तेज़ी से होते हैं (हमारे विशिष्ट मामले में वे स्मृति में स्थित होंगे और कई धागे से एक्सेस होंगे, अक्सर प्रत्येक में 10-1000 आइटम होते हैं) – karl25233

उत्तर

7

आप अधिक विवरण देना चाहिए, लेकिन एक ही विकल्प System.Collections.ObjectModel.ReadOnlyCollection<> जो एक सूची/सरणी के रूप में कार्य करता है। यह इस तरह से बनाया जा सकता है:

var immutable1 = Array.AsReadOnly(new[] { 7, 9, 13, }); 
    var immutable2 = (new List<int> { 7, 9, 13, }).AsReadOnly(); 

यह एक IList<> के चारों ओर एक आवरण है। इसे किसी भी चीज पर नहीं डाला जा सकता है जो अंतर्निहित सूची/सरणी को बदलने की अनुमति देता है। लेकिन अंतर्निहित वस्तु को निश्चित रूप से प्रतिबिंब के साथ पहुंचा जा सकता है।

कहीं किसी और "आंतरिक" सूची/सरणी, कि ReadOnlyCollection<> आवरण में refelcted किया जाएगा mutates हैं। कोई प्रति नहीं किया जाता है।

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


एक सस्ता बात करने के लिए सिर्फ इंटरफेस IReadOnlyList<out T> जो T में covariant है (एक अतिरिक्त लाभ) का प्रयोग है। List<T> और T[] दोनों इस इंटरफ़ेस को लागू करते हैं। तो:

IReadOnlyList<int> immutable3 = new[] { 7, 9, 13, }; 
    IReadOnlyList<int> immutable4 = new List<int> { 7, 9, 13, }; 

उस मामले में, हालांकि, उपभोक्ता immutable3 as IList<int>, उदाहरण के लिए, या immutable3 as int[] परीक्षण कर सकते हैं, और परिवर्तनशील वस्तु (प्रतिबिंब के बिना) के लिए एक "अस्थायी प्रकार संदर्भ" मिलता है।


हालांकि, वहाँ (जैसे ImmutableList<> के रूप में) अपरिवर्तनीय प्रकार है कि "बीटा में" Microsoft.Immutable.Collections में नहीं हैं। तो आप इसे स्थापित करने पर विचार कर सकते हैं कि अगर आपको वास्तव में इसकी आवश्यकता है। यह मानक .NET लाइब्रेरी का हिस्सा नहीं है, इसलिए आपको इसे अलग से इंस्टॉल करना होगा।


"उथले" से मेरा क्या मतलब है, इसका विस्तार करने के लिए, मान लीजिए कि आपके पास एक सरणी है जिसका तत्व प्रकार स्वयं ही उत्परिवर्तनीय है। फिर कोई फर्क नहीं पड़ता कि आप ऊपर दिए गए सुझावों का उपयोग करते हैं, लोग अभी भी प्रविष्टियों को जोड़ सकते हैं। उदाहरण के लिए:

StringBuilder[] yourArray = { 
    new StringBuilder("All"), 
    new StringBuilder("is"), 
    new StringBuilder("good"), 
    }; 

var immutable = ImmutableList<StringBuilder>.Empty.AddRange(yourArray); 

immutable[0].Insert(0, "NOT "); 
immutable[1].Clear(); 
immutable[2].Append(new string('!', 10000)); 
+1

इसके अलावा, ध्यान दें कि पठनीय संग्रह एक प्रतिलिपि नहीं है। तो आपको यह सुनिश्चित करना होगा कि अंतर्निहित सूची/सरणी लीक नहीं हुई है, क्योंकि वह रीडोनली रैपर को भी बदल देगा। – Luaan

+0

@ लुआन अच्छा बिंदु। मैंने अब अपने जवाब में इसका उल्लेख किया है। –

+0

अपरिवर्तनीय संग्रह NuGet पैकेज * अभी भी बीटा (या कम से कम आरसी स्थिति) है: "सिस्टम। चयन। Imutable 1.1.34 ** - आरसी **" – Brandon

1

नुकसान के लिए बस का उपयोग कर ReadOnlyCollection या IReadOnlyList कि इन अपरिवर्तनीय सरणी की तुलना में काफी कमजोर गारंटी प्रदान करता है। ये ऑब्जेक्ट केवल गारंटी देते हैं कि केवल पढ़ने के संग्रह के धारक इसे संशोधित नहीं करेंगे। वे गारंटी नहीं देते हैं कि संग्रह कोड द्वारा संशोधित नहीं किया जाएगा जिसमें अंतर्निहित संग्रह का संदर्भ है।

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

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

LINQ अपने आप को लागू करने में बहुत आसान बनाता है, हालांकि यह बहुत स्मार्ट नहीं है। एक आइटम को एक अचूक तरीके से एक सरणी में निकालने का एक उदाहरण:

private int[] _array; 

public void RemoveItem(int item) 
{ 
    _array = _array.Where(x => x != item).ToArray(); 
} 

/// <summary>Gets immutable array</summary> 
public IReadOnlyList<int> Data { get { return _array; } } 
+0

ठीक है, जानकारी के लिए धन्यवाद :) मुझे लगता है कि ImmutableList अब तक का सबसे अच्छा विकल्प होगा। – karl25233

+0

उस चिंता का सामना करने का एक तरीका संपूर्ण सूची/सरणी की प्रतिलिपि बनाना है और फिर _copy_ को 'ReadOnlyCollection <>' में लपेटें (या प्रतिलिपि को 'IReadOnlyList <> ') में अपस्टास्ट करें। यदि आप इसे 'var safe = originalArray.ToList() के रूप में लिखते हैं। AsReadOnly();' आप सुनिश्चित कर सकते हैं कि किसी को भी मध्यवर्ती 'सूची <> 'बनाया गया संदर्भ नहीं है (क्योंकि आप उस संदर्भ को नहीं रखते हैं)। –

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