2012-04-10 21 views
5

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

+4

शायद आपको structs और कक्षाओं के बीच निर्णय लेने के लिए अपने तर्क को फिर से सोचने की आवश्यकता है। –

उत्तर

14

मेरी मूल्य प्रकार के कुछ काफी बड़े स्मृति पदचिह्न

चलता है कि वे मूल्य प्रकार नहीं होना चाहिए देखने का एक कार्यान्वयन बिंदु से, है। "वर्ग पुस्तकालय विकास के लिए डिजाइन दिशानिर्देश", खंड "Choosing Between Classes And Structures" से:, आदिम के समान

  • यह तार्किक एक भी मूल्य का प्रतिनिधित्व करता:

    जब तक प्रकार निम्नलिखित विशेषताएं के सभी है एक संरचना को परिभाषित नहीं है प्रकार (पूर्णांक, डबल, और इतने पर)।

  • इसका एक उदाहरण आकार 16 बाइट से छोटा है।
  • यह अपरिवर्तनीय है।
  • इसे अक्सर बॉक्सिंग नहीं करना पड़ेगा।

ऐसा लगता है आप अपरिवर्तनीय संदर्भ बनाने की जानी चाहिए की तरह प्रकार के बजाय। कई मायनों में वे वैल्यू ऑब्जेक्ट्स की तरह "महसूस" करते हैं (स्ट्रिंग्स सोचते हैं) लेकिन आपको उन्हें पास करने की दक्षता के बारे में चिंता करने की आवश्यकता नहीं होगी।

"अचल स्थिति" मान प्रकार के लिए एक से थोड़ा तरल पदार्थ अवधारणा है - और यह निश्चित रूप से इसका मतलब यह नहीं है किref का उपयोग कर सुरक्षित है:

// int is immutable, right? 
int x = 5; 
Foo(ref x); 
Console.WriteLine(x); // Eek, prints 6... 
... 
void Foo(ref int y) 
{ 
    y = 6; 
} 

हम मूल्य की एक हिस्सा नहीं बदल रहे हैं - हम पूरी तरह से अलग मूल्य के साथ x के पूरे मूल्य को बदल रहे हैं।

अचल स्थिति कुछ हद तक जब यह संदर्भ के लिए प्रकार आता है के बारे में सोचने के लिए आसान है - हालांकि फिर भी आप एक वस्तु जो अपने आप में परिवर्तन नहीं होगा हो सकता है, लेकिन परिवर्तनशील वस्तुओं का उल्लेख कर सकते ...

+0

"इसमें 16 बाइट से छोटा उदाहरण है"। क्या आप वास्तव में 'कक्षा वेक्टर 3 डी' लिखते हैं, क्योंकि इसमें 24 बाइट हैं? – hansmaad

+2

@ हंसमाद यह सिर्फ एक दिशानिर्देश है। हर मामले को इसमें शामिल नहीं किया जा सकता है, लेकिन निर्णय लेने पर विचार करने के लिए वे चीजें/नियम हैं। – vcsjones

+3

@ हंसमाद: यदि प्रकार * मूल्य से * पास होने की संभावना है, तो * हाँ *, आपको चाहिए। यदि मूल्य प्रकार मूल्य से पारित होने की संभावना नहीं है - यदि आप केवल एक बनाते हैं और इसे बिना किसी अन्य विधि के पास स्थानीय रूप से उपयोग करते हैं - तो आगे बढ़ें और यदि आप चाहें तो इसे बड़ा बनाएं। –

3

तो मुझे आश्चर्य है कि संदर्भ के द्वारा हमेशा अपरिवर्तनीय मूल्य वस्तुओं को पारित करना एक अच्छा विचार है? चूंकि वस्तुएं अपरिवर्तनीय हैं, इसलिए वे उन तरीकों से संशोधित नहीं कर सकते हैं जो संदर्भ द्वारा उन्हें स्वीकार करते हैं। संदर्भ द्वारा गुजरते समय क्या अन्य मुद्दे हैं?

यह बिल्कुल स्पष्ट नहीं है कि आपका क्या मतलब है। यह मानते हुए कि आप इसे ref या out पैरामीटर के रूप में पास करने का मतलब रखते हैं, तो विधि केवल संग्रहण स्थान पर एक नया उदाहरण असाइन कर सकती है। इससे कॉलर क्या देखता है संशोधित करेगा क्योंकि कॉलर द्वारा पारित स्टोरेज स्थान के लिए कैली में संग्रहण स्थान उपनाम है।

यदि आप struct के उदाहरणों की प्रतिलिपि बनाने के कारण स्मृति समस्याओं से निपट रहे हैं, तो आपको string की तरह एक अपरिवर्तनीय संदर्भ प्रकार बनाने पर विचार करना चाहिए।

11

जॉन की जवाब पाठ्यक्रम सही है; मैं इसे इसमें जोड़ूंगा: मान प्रकार पहले से संदर्भ द्वारा पारित होते हैं जब आप मान प्रकार पर कोई विधि कॉल करते हैं। उदाहरण के लिए:

struct S 
{ 
    int x; 
    public S(int x) { this.x = x; } 
    public void M() { Console.WriteLine(this.x); } 
} 

विधि एम() तार्किक रूप में एक ही बात है:

public static void M(ref S _this) { Console.WriteLine(_this.x); } 

जब भी आप एक struct पर एक उदाहरण विधि कॉल, हम एक रेफरी पारितचर है कि कॉल का रिसीवर था।

तो क्या होगा यदि रिसीवर एक चर नहीं है? फिर मान को अस्थायी चर में कॉपी किया गया है जिसका उपयोग रिसीवर के रूप में किया जाता है। और यदि मूल्य बड़ा है, तो यह संभावित रूप से एक महंगी प्रति है!

मूल्य प्रकारों को मूल्य द्वारा प्रतिलिपि बनाई जाती है; यही कारण है कि उन्हें मूल्य प्रकार कहा जाता है। जब तक आप पर सभी संभावित महंगे प्रतियों को ढूंढने और उन्हें समाप्त करने के बारे में बेहद सावधान होने की योजना बना रहे हैं, तो मैं फ्रेमवर्क डिज़ाइन दिशानिर्देश की सलाह का पालन करता हूं: 16 बाइट्स के नीचे structs रखें, और उन्हें मूल्य से पास करें।

मैं यह भी जोर दूंगा कि जॉन सही है: रेफरी द्वारा एक संरचना को पास करने का मतलब है एक चर के संदर्भ को पास करना, और चर बदल सकते हैं। यही कारण है कि उन्हें "चर" कहा जाता है। सी ++ में सी # में कोई "कॉन्स रेफरी" नहीं है; भले ही मूल्य का प्रकार स्वयं "अपरिवर्तनीय" प्रतीत होता है, इसका मतलब यह नहीं है कि परिवर्तनीय इसे अपरिवर्तनीय है। आप इस काल्पनिक लेकिन शैक्षिक उदाहरण में है कि का एक चरम उदाहरण देख सकते हैं:

struct S 
{ 
    readonly int x; 
    public S(int x) { this.x = x; } 
    public void M(ref S s) 
    { 
     Console.WriteLine(this.x); 
     s = new S(this.x + 1); 
     Console.WriteLine(this.x); 
    } 
} 

क्या यह संभव है एम दो अलग नंबरों को लिखने के लिए के लिए? आप मूर्खता से सोचेंगे कि संरचना अपरिवर्तनीय है, और इसलिए एक्स बदल नहीं सकता है। लेकिन दोनों रों और इसचर, और चर बदल सकता है:

S q = new S(1); 
q.M(ref q); 

कि 1 प्रिंट, 2 क्योंकि this और sq करने के लिए दोनों संदर्भ हैं, और कुछ भी नहीं बदलने से q रोक रहा है ; यह पढ़ा नहीं जाता

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

+0

तथाकथित अपरिवर्तनीय structs को उत्परिवर्तनीय दिखाया जा सकता है, भले ही उनके कोड में कुछ भी इस तरह के उत्परिवर्तन में सहयोग न करे। उदाहरण के लिए, भले ही 'KeyValuePair ' का भंडारण स्थान परमाणु रूप से लिखा जा सके (चूंकि इसमें 32 बिट्स लगते हैं), ऐसे भंडारण स्थान पर एक थ्रेड 'ToString()' होने पर, अन्य थ्रेड मान को अपडेट करता है, वहां 'ToString' हो सकता है 'पुरानी 'Key.ToString()' को वापस करने के लिए '' t.TString() 'के साथ संयोजित। – supercat