2012-04-06 15 views
13

पर असाइन करें मुख्य प्रश्न यह है कि इस कीवर्ड को उपयोगिता और स्मृति के संबंध में संशोधित करने की अनुमति देने के प्रभाव क्या हैं; और यह सी # भाषा विनिर्देशों में क्यों अनुमति है?इस कीवर्ड को C#

अन्य प्रश्न/उपपृष्ठों का उत्तर दिया जा सकता है या नहीं, अगर ऐसा करना है। मैंने सोचा कि उनके जवाब उत्तर मुख्य प्रश्न के उत्तर को स्पष्ट करने में मदद करेंगे।

मैं What's the strangest corner case you've seen in C# or .NET?

public struct Teaser 
{ 
    public void Foo() 
    { 
     this = new Teaser(); 
    } 
} 

के जवाब के रूप में इस भर में भाग गया मैं चारों ओर क्यों सी # भाषा विनिर्देशों भी इस अनुमति होगी मेरे सिर लपेटो करने की कोशिश कर रहा हूँ। उप-भाग 1। क्या ऐसा कुछ भी है जो को उचित ठहराने वाला होगा संशोधित हो सकता है? क्या यह हर उपयोगी है?

कि जवाब देने के लिए टिप्पणियों में से एक सी # के माध्यम से

CLR से था: कारण वे इस बनाया है, क्योंकि आप एक और निर्माता में एक struct के parameterless निर्माता कॉल कर सकते हैं। यदि आप केवल एक संरचना के एक मान को प्रारंभ करना चाहते हैं और अन्य मान शून्य/शून्य (डिफ़ॉल्ट) होना चाहते हैं, तो आप सार्वजनिक Foo (int bar) {this = new foo() लिख सकते हैं; विशेष वार = बार;}। यह कुशल नहीं है और वास्तव में उचित नहीं है (विशेष वार दो बार असाइन किया गया है), लेकिन बस FYI। (यही कारण है कि पुस्तक में दी गई है, मैं क्यों हम सिर्फ सार्वजनिक फू (पूर्णांक बार नहीं करना चाहिए पता नहीं है): इस())

उप-भाग 2. मैं नहीं कर रहा हूँ यकीन है कि मैं उस तर्क का पालन करता हूं। क्या कोई इसका अर्थ स्पष्ट कर सकता है? शायद इसका एक ठोस उदाहरण कैसे इस्तेमाल किया जाएगा?

संपादित करें (उपेक्षा ढेर या ढेर मुख्य बिंदु स्मृति रिहाई या कचरा संग्रहण के संबंध में है। इसके बजाय पूर्णांक [] आपको लगता है कि 262,144 सार्वजनिक पूर्णांक क्षेत्रों के साथ की जगह सकता है) इसके अलावा मेरी समझ structs से के रूप में स्टैक पर बनाई गई हैं ढेर करने का विरोध करता है, तो इस struct जब फू कहा जाता है एक 1 एमबी बाइट सरणी क्षेत्र इतना

public int[] Mb = new int[262144]; 

उप-भाग 3. यह कभी ढेर से भी निकल जाते है के रूप में प्रारंभ करने के लिए कर रहे थे? मेरे लिए ऐसा लगता है क्योंकि संरचना कभी भी गुंजाइश से बाहर नहीं गई थी, इसे ढेर से हटाया नहीं जाएगा। टेस्ट केस बनाने के लिए आज रात नहीं है लेकिन शायद मैं कल इसके लिए करूँगा।

नीचे कोड

Teaser t1 = new Teaser(); 
Teaser tPlaceHolder = t1; 
t1.Foo(); 

उप-भाग 4 में

। क्या टी 1 और टीप्लेस होल्डर एक ही या अलग पता स्थान पर कब्जा कर रहे हैं?

3 साल पुरानी पोस्ट लाने के लिए खेद है, लेकिन इसने मुझे वास्तव में अपना सिर खरोंच कर लिया है।

एफवाईआई स्टैक ओवरफ्लो पर पहला सवाल है, इसलिए अगर मुझे प्रश्न के साथ कुछ गलत मिला तो कृपया एक टिप्पणी पोस्ट करें और मैं संपादित करूंगा।

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

+3

1 में 4 प्रश्न स्टैक ओवरफ़्लो के लिए उपयुक्त नहीं हैं। एक प्रश्न * एक प्रश्न होना चाहिए। * –

+4

@ एंथनीपेग्राम - इस मामले में मुझे लगता है कि यह प्रश्न मुख्य प्रश्न की ओर उपेक्षा हैं, इस तरह से structs वास्तव में काम करते हैं – Polity

+1

मेरी माफ़ी नहीं है कि यह सब एक में कैसे पेश किया जाए। मुझे लगता है कि मुख्य प्रश्न यह है कि इस कीवर्ड को संशोधित करने की इजाजत देने के पक्ष में क्या प्रभाव पड़ता है? प्रश्न 3-4 साइड इफेक्ट्स हैं जिन्हें मैंने सोचा था कि एक संभावना हो सकती है। अगर किसी के पास मेरे अलावा प्रश्न संपादित करने की शक्ति है और सोचता है कि वे इसे बेहतर तरीके से पूछ सकते हैं तो कृपया ऐसा करने में संकोच न करें। या एक बेहतर सवाल का सुझाव देने वाली टिप्पणी छोड़ दो और मैं खरोंच से शुरू करूंगा। –

उत्तर

6

सबसे पहले, मुझे लगता है कि अगर आप सही प्रश्न पूछ रहे हैं तो आपको जांच करके शुरू करना चाहिए। शायद हमें पूछना चाहिए, "सी # क्यों नहीं एक संरचना में this असाइनमेंट की अनुमति देता है?"

संदर्भ प्रकार में this कीवर्ड को असाइन करना संभावित रूप से खतरनाक है: आप उस वस्तु के संदर्भ को ओवरराइट कर रहे हैं जिसकी विधि आप चल रहे हैं; आप उस संदर्भ को शुरू करने वाले निर्माता के भीतर भी ऐसा कर सकते हैं। यह स्पष्ट नहीं है इसका क्या व्यवहार होना चाहिए। इसे समझने से बचने के लिए, क्योंकि यह आमतौर पर उपयोगी नहीं है, इसलिए इसे spec (या कंपाइलर) द्वारा अनुमति नहीं है।

this कीवर्ड को मूल्य प्रकार में असाइन करना, हालांकि , अच्छी तरह से परिभाषित किया गया है। मूल्य प्रकारों का असाइनमेंट एक प्रतिलिपि है। प्रत्येक फ़ील्ड का मान आवर्ती रूप से असाइनमेंट के दाएं से बाएं तरफ से कॉपी किया जाता है। यह संरचना पर एक पूरी तरह से सुरक्षित संचालन है, यहां तक ​​कि एक कन्स्ट्रक्टर में, becaus ई संरचना की मूल प्रति अभी भी मौजूद है, आप बस अपना डेटा बदल रहे हैं। यह संरचना में प्रत्येक फ़ील्ड मैन्युअल रूप से सेट करने के बराबर है। Spec या compiler को ऐसे ऑपरेशन को क्यों रोकना चाहिए जो अच्छी तरह से परिभाषित और सुरक्षित है?

यह वैसे, आपके उप-प्रश्नों में से एक का उत्तर देता है। वैल्यू टाइप असाइनमेंट एक गहरी प्रतिलिपि ऑपरेशन है, संदर्भ प्रति नहीं।

Teaser t1 = new Teaser(); 
Teaser tPlaceHolder = t1; 
t1.Foo(); 

आप अपने Teaser संरचना की दो प्रतियां आवंटित की है, और दूसरे में खेतों में पहले में क्षेत्रों के मूल्यों की नकल की: इस कोड को देखते हुए। यह मूल्य प्रकारों की प्रकृति है: दो प्रकार के समान फ़ील्ड समान हैं, जैसे कि दो int वेरिएबल्स जिनमें दोनों होते हैं, समान हैं, भले ही वे "स्मृति में" हों।

इसके अलावा, यह महत्वपूर्ण है और दोहराने लायक है: सावधान रहना "ढेर" बनाम "ढेर" पर क्या होता है। मूल्य के प्रकार हर समय ढेर पर समाप्त होते हैं, जिस संदर्भ में उनका उपयोग किया जाता है। अल्पकालिक (स्थानीय रूप से स्कॉप्ड) structs जो बंद नहीं होते हैं या अन्यथा उनके दायरे से बाहर नहीं उठाए जाते हैं, उन्हें ढेर पर आवंटित होने की संभावना है। लेकिन यह महत्वहीन implementation detail है कि आपको न तो परवाह करना चाहिए और न ही भरोसा करना चाहिए। कुंजी यह है कि वे मूल्य प्रकार हैं, और इस तरह व्यवहार करते हैं।

जहां तक ​​this पर कितना उपयोगी असाइनमेंट वास्तव में है: बहुत नहीं। विशिष्ट उपयोग मामलों का पहले ही उल्लेख किया गया है। आप इसका उपयोग डिफ़ॉल्ट रूप से डिफ़ॉल्ट मानों के साथ एक संरचना को प्रारंभ करने के लिए कर सकते हैं लेकिन एक छोटी संख्या निर्दिष्ट करें।

public void SwapValues(MyStruct other) 
{ 
    var temp = other; 
    other = this; 
    this = temp; 
} 

कि परे:

public struct Foo 
{ 
    // Fields etc here. 

    public Foo(int a) 
    { 
    this = new Foo(); 
    this.a = a; 
    } 
} 

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

+0

+1 बंद होने से पहले प्रयास करने के लिए +1। मैं कल कुछ समय इस सवाल को फिर से शुरू करने की कोशिश करूंगा। –

+0

मैंने मतदान करने का फैसला किया यह जवाब है और एक नया फिर से खोलना नहीं है। मूल्य से प्रतिलिपि यह है कि आखिरकार इसमें डूब गया। मुझे लगता है कि मेरे दिमाग में मैंने हमेशा "इस" को संदर्भ के रूप में सोचा है और "इस" के संदर्भ में विचार नहीं कर रहा था, जैसा कि structs से निपटने के दौरान मूल्य प्रकार का जिक्र है। मुझे लगता है कि मैंने इस कीवर्ड को किसी भी structs में भी इस्तेमाल नहीं किया है। –

1

यह असाइन करने योग्य होने के साथ 'उन्नत' कोने के मामलों को structs के साथ अनुमति देता है। एक उदाहरण मैंने पाया एक स्वैप विधि थी:

struct Foo 
{ 
    void Swap(ref Foo other) 
    { 
     Foo temp = this; 
     this = other; 
     other = temp; 
    } 
} 

मैं दृढ़ता से यह इस्तेमाल के खिलाफ तर्क है, क्योंकि यह डिफ़ॉल्ट 'वांछित' एक struct जो अचल स्थिति है की प्रकृति का उल्लंघन करती है। इस विकल्प को चारों ओर रखने का कारण तर्कसंगत अस्पष्ट है।

अब जब यह स्वयं को structs की बात आती है। वे कुछ तरीकों से कक्षाओं से भिन्न होते हैं:

  • वे प्रबंधित ढेर के बजाय ढेर पर रह सकते हैं।
  • उन्हें अप्रबंधित कोड पर वापस मार्शल किया जा सकता है।
  • उन्हें एक पूर्ण मूल्य के लिए असाइन नहीं किया जा सकता है।

इसकी पूरी जानकारी के लिए देखें: http://www.jaggersoft.com/pubs/StructsVsClasses.htm

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

.NET में एक सरणी ढेर पर आवंटित डिफ़ॉल्ट है (यह व्यवहार असुरक्षित कोड और स्टैकलॉक कीवर्ड का उपयोग करते समय संगत नहीं है)। उपर्युक्त स्पष्टीकरण पर वापस जाकर, यह इंगित करेगा कि संरचना के उदाहरण भी ढेर पर आवंटित किए जाते हैं। वास्तव में, यह साबित करने का एक आसान तरीका आकार में 1 एमबी की सरणी आवंटित करना और निरीक्षण करना है कि कैसे कोई स्टैक ओवरफ्लो अपवाद फेंक दिया गया है।

ढेर पर एक उदाहरण के लिए जीवनकाल इसके दायरे से निर्धारित होता है। यह प्रबंधक ढेर पर एक उदाहरण से अलग है जो जीवनकाल कचरा कलेक्टर द्वारा निर्धारित किया जाता है (और क्या उस घटना के प्रति अभी भी संदर्भ हैं)। आप यह सुनिश्चित कर सकते हैं कि ढेर पर कुछ भी तब तक रहता है जब तक यह दायरे में न हो। स्टैक पर एक उदाहरण आवंटित करना और एक विधि को कॉल करना उस उदाहरण को तब तक नहीं रोक देगा जब तक कि उस उदाहरण को दायरे से बाहर नहीं किया जाता है (डिफ़ॉल्ट रूप से जब उस विधि में जिस विधि को घोषित किया गया था)।

एक स्ट्रेट कैंट ने इसके प्रति संदर्भ प्रबंधित नहीं किए हैं (पॉइंटर्स अप्रबंधित कोड में संभव हैं)। सी # में ढेर पर structs के साथ काम करते समय, आप मूल रूप से एक संदर्भ के बजाय एक उदाहरण के लिए एक लेबल है। एक स्ट्रक्चर को दूसरे में असाइन करना केवल अंतर्निहित डेटा की प्रतिलिपि बनाता है। आप संदर्भों के रूप में संदर्भ देख सकते हैं। निष्क्रिय रूप से, एक संदर्भ एक संरचना से अधिक कुछ नहीं है जिसमें स्मृति में एक निश्चित भाग के लिए सूचक होता है। दूसरे के लिए एक संदर्भ निर्दिष्ट करते समय, पॉइंटर डेटा कॉपी हो जाता है।

// declare 2 references to instances on the managed heap 
var c1 = new MyClass(); 
var c2 = new MyClass(); 

// declare 2 labels to instances on the stack 
var s1 = new MyStruct(); 
var s2 = new MyStruct(); 

c1 = c2; // copies the reference data which is the pointer internally, c1 and c2 both point to the same instance 
s1 = s2; // copies the data which is the struct internally, c1 and c2 both point to their own instance with the same data 
+0

मुझे लगता है कि यह स्टैक पर या इसके प्रतिलिपि की परवाह किए बिना फू को कॉल करते समय ढेर जीसी अंततः मूल संरचना से जुड़ी मेमोरी को साफ करेगा? बस स्पष्ट करने के लिए मैं सख्ती से प्रबंधित कोड की बात कर रहा हूं। ओह और फू द्वारा मेरा मतलब था टीज़र संरचना में फू आपके फू स्ट्रक्चर नहीं। –

+0

जीसी केवल प्रबंधित ढेर पर आवंटित उदाहरणों को साफ करेगा। ढेर आधारित उदाहरण वास्तव में वास्तव में साफ नहीं होते हैं (इसलिए, एक संरचना में एक विनाशक शामिल नहीं हो सकता है)। दायरे से बाहर एक बार उनका लेबल अवैध हो जाएगा। इस पोस्ट में एरिक लिपर्ट का जवाब देखें: http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope – Polity

+0

structs मान प्रकार हैं; वे कभी स्पष्ट रूप से कचरा इकट्ठा नहीं होते हैं। मान प्रकारों के लिए स्मृति ओएस को वापस कर दिया जाता है जब मान प्रकार के दायरे का दायरा होता है; यदि यह एक स्थानीय चर या पैरामीटर है, तो यह तब होता है जब फ़ंक्शन रिटर्न होता है। यदि यह एक क्षेत्र है, तो ऐसा होता है जब इसकी कंटेनर कक्षा जीसीडी होती है। आदि –

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