2009-02-18 18 views
29

मान लीजिए मैं एक सामान्य एक struct प्रकार के मूल्यों से युक्त सूची की घोषणा:सी # में, सूची <struct> बॉक्स में मूल्य हैं?

struct MyStruct { 
    public MyStruct(int val1, decimal val2) : this() { 
     Val1 = val1; 
     Val2 = val2; 
    } 
    public int Val1 {get; private set;} 
    public decimal Val2 {get; private set;} 
} 

List<MyStruct> list; 

करता सूची <> दुकान एक बॉक्स्ड struct के रूप में प्रत्येक व्यक्ति के मूल्य, ढेर पर व्यक्तिगत रूप से आवंटित? या यह उससे ज्यादा चालाक है?

उत्तर

33

कोई मुक्केबाजी नहीं है।

"नहीं, कोई मुक्केबाजी नहीं होगी। यह जेनेरिक के मुख्य डिजाइन लक्ष्यों में से एक था।"

http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/359cf58a-f53d-478e-bc31-1507e77c9454/

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

http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx

+0

क्या करता है "और 500 सूची तत्वों के बाद स्मृति को सहेजा गया है, मुक्केबाजी सूची तत्व वर्ग कार्यान्वयन उत्पन्न करने के लिए उपयोग की जाने वाली स्मृति से अधिक नहीं है" मतलब? क्या यह किसी तरह का नुकसान है? –

+0

@ मार्सनमाओ कोई नुकसान नहीं है। दूसरे शब्दों में रखो, इसका मतलब है कि यदि कोई सूची बेवकूफ थी और उसने बॉक्स स्ट्रक्चर किया था, तो सूची द्वारा उपयोग की जाने वाली स्मृति लगभग 500 तत्वों पर दोगुनी हो जाएगी। चूंकि, यह बॉक्स स्ट्रक्चर नहीं करता है, तो 500 तत्वों द्वारा उपयोग की जाने वाली मेमोरी की तुलना में काफी कम होगी। –

+0

@ सी में मार्सन माओ जेनेरिक सी ++ की तरह नहीं हैं, वे हमेशा प्रत्येक अद्वितीय प्रकार के लिए कोड उत्पन्न नहीं करते हैं। संदर्भ प्रकारों के लिए वे एक ही अंतर्निहित कोड का उपयोग करेंगे क्योंकि सूचक के आकार संदर्भ के प्रकार के साथ नहीं बदलते हैं। लेकिन मूल्य प्रकारों के लिए आकार बदलता है इसलिए सूची का एक संस्करण विशिष्ट रूप से जेनरेट किया जाना चाहिए, इसकी स्मृति लागत है क्योंकि इसका मतलब है कि अब सूची कोड की एक और प्रति है। क्षमा करें अगर मैं स्पष्ट नहीं हूं। Https://msdn.microsoft.com/en-us/library/f4a6ta2h.aspx –

1

कोई मुक्केबाजी नहीं है, यही कारण है कि यह गैर-सामान्य तरीके से थोड़ा तेज है।

8

नहीं, List<T> कुछ भी बॉक्स नहीं करता है। आंतरिक रूप से यह अपने मानों को एक साधारण सरणी में संग्रहीत करता है:

public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable 
{ 
    // Fields 
    private const int _defaultCapacity = 4; 
    private static T[] _emptyArray; 
    private T[] _items; 
    private int _size; 
0

कोई मुक्केबाजी, कि Benefits of Generics में से एक है:

List<int> list1 = new List<int>();  
// No boxing, no casting: 
list1.Add(3); 

// Compile-time error: 
// list1.Add("It is raining in Redmond."); 
2

सूची प्रकार टी की सरणियों में सब कुछ संग्रहीत करता है कोई मुक्केबाजी नहीं है, लेकिन सरणी ढेर पर आवंटित किया जाता है।

19

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

और किसी भी तरह से, खेतों का पर्दाफाश न करें! गुण का प्रयोग करें ;-p

उदाहरण के लिए:

struct MyStruct { 
    public MyStruct(int val1, decimal val2) { 
     this.val1 = val1; 
     this.val2 = val2; 
    } 
    private readonly int val1; 
    private readonly decimal val2; 
    public int Val1 {get {return val1;}} 
    public decimal Val2 {get {return val2;}} 
} 

या वैकल्पिक रूप से (सी # 3.0):

struct MyStruct { 
    public MyStruct(int val1, decimal val2) : this() { 
     Val1 = val1; 
     Val2 = val2; 
    } 
    public int Val1 {get; private set;} 
    public decimal Val2 {get; private set;} 
} 
+0

देखें, मैं इसकी सराहना करता हूं। कई लोगों ने इसे इंगित करते हुए देखते हुए, मैं मूल संरचना में अपनी संरचना का उपयोग करूंगा, ताकि मुक्केबाजी पर जोर दिया जा सके और structs के मूल्य अर्थशास्त्र को बंद कर दिया जा सके। –

3
typeof(List<>) // or informally List`1 

... एक सामान्य प्रकार है। जेनेरिक प्रकार या पैरामीटरयुक्त प्रकार विशेष होते हैं कि उन्हें सामान्य तरीके से संकलित किया जाता है लेकिन रन-टाइम पर वे फिर भी उनके उपयोग के आधार पर संकलित किए जाते हैं।

यदि आप एक सामान्य सूची में ValueType डालते हैं उदा।सूची < int> रन-टाइम व्यवहार खतरे में है जैसे कि यह प्रकार int को संग्रहीत कर रहा था (जो प्रति-दर-मूल्य है)। मुक्केबाजी की आवश्यकता नहीं है क्योंकि आपको इलाज करने की आवश्यकता नहीं है जैसे कि इस सूची`1 का प्रकार int के अलावा कुछ और है।

.NET 2.0 से पहले यह नहीं किया जा सका इसलिए कुख्यात ऐरेलिस्ट क्लास ने ऑब्जेक्ट्स की एक सरणी बनाए रखी जिसका मतलब वैल्यू टाइप (इनट्स या स्ट्रक्चर) को उस कंटेनर में रखा जाना था।

जावा जेनिक्स के साथ भ्रमित नहीं होना चाहिए जो कुछ अलग है। जावा जेनरिक को टाइप एरर के साथ कार्यान्वित किया गया था जो आपको वही प्रदर्शन बढ़ावा नहीं देता है। जावा क्या करता है कि एक बार जब कंपाइलर टाइप टाइपिंग समाप्त हो जाता है, तो यह सब कुछ ऑब्जेक्ट करने के लिए डालेगा। यही कारण है कि आप .NET जेनेरिक प्रकार सिस्टम के साथ जावा जेनरिक के साथ प्रतिबिंब नहीं कर सकते हैं।

+0

मुझे रनटाइम संकलन के बारे में पता नहीं था ... यह दिलचस्प है। जावा जानकारी के लिए भी +1। –

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