2009-11-17 17 views
91

मैं ऑटो-कार्यान्वित गुणों का उपयोग कर रहा हूं। मुझे लगता है कि निम्नलिखित को ठीक करने का सबसे तेज़ तरीका है अपना बैकिंग वैरिएबल घोषित करना?रिटर्न वैल्यू त्रुटि को संशोधित नहीं कर सकता C#

public Point Origin { get; set; } 

Origin.X = 10; // fails with CS1612 

त्रुटि संदेश: 'अभिव्यक्ति' क्योंकि यह एक चर

का प्रयास एक मूल्य के प्रकार है कि एक मध्यवर्ती का परिणाम था संशोधित करने के लिए बनाया गया था नहीं है के रिटर्न मान संशोधित नहीं कर सकते अभिव्यक्ति। क्योंकि मान जारी नहीं है, मान अपरिवर्तित होगा।

इस त्रुटि को हल करने के लिए, अभिव्यक्ति का परिणाम मध्यवर्ती मान में संग्रहीत करें, या मध्यवर्ती अभिव्यक्ति के लिए संदर्भ प्रकार का उपयोग करें।

+12

यह एक और उदाहरण है कि क्यों परिवर्तनीय मूल्य प्रकार एक बुरा विचार है। यदि आप मूल्य प्रकार को म्यूट करने से बच सकते हैं, तो ऐसा करें। –

+0

निम्नलिखित कोड लें (एक निश्चित ईएल :-) द्वारा ब्लॉग किए गए एएसटर कार्यान्वयन में मेरे प्रयासों से, जो एक मान प्रकार को बदलने से नहीं बचा सकता: कक्षा पथ : IENumerable जहां टी: इनोड, नया() {... } सार्वजनिक हेक्सनोड (int x, int y): यह (नया प्वाइंट (x, y)) {} पथ पथ = नया पथ (नया टी (x, y)); // त्रुटि // बदसूरत ठीक पथ पथ = नया पथ (नया टी()); पथ। LastStep.Centre = नया प्वाइंट (एक्स, वाई); –

उत्तर

128

ऐसा इसलिए है क्योंकि Point एक मान प्रकार (struct) है।

इस वजह से

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

तुम सिर्फ X मूल्य में परिवर्तन करना चाहते हैं, तो आप कुछ इस तरह करने की जरूरत है:

Origin = new Point(10, Origin.Y); 
+1

@ पॉल: क्या आपके पास संरचना को कक्षा में बदलने की क्षमता है? – Doug

+0

यह एक प्रकार का बमर है, क्योंकि संपत्ति सेटर आईएम असाइनिंग का दुष्प्रभाव होता है (संरचना बैकिंग संदर्भ प्रकार में देखने के रूप में कार्य करती है) – Alexander

+0

एक और समाधान यह है कि बस अपनी संरचना को कक्षा में बनाना है। सी ++ के विपरीत, जहां एक वर्ग और संरचना केवल डिफ़ॉल्ट सदस्य पहुंच (निजी और सार्वजनिक, क्रमशः) से भिन्न होती है, सी # में structs और कक्षाओं में कुछ और अंतर होते हैं। यहां कुछ और जानकारी दी गई है: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/ – Artorias2718

6

बैकिंग चर का उपयोग करने से कोई मदद नहीं मिलेगी। Point प्रकार एक मान प्रकार है।

आप उत्पत्ति संपत्ति के लिए पूरे अंक मान असाइन करना होगा: -

Origin = new Point(10, Origin.Y); 

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

get { return myOrigin; } 

तुम अब भी प्वाइंट संरचना की एक प्रति लौटने होगी और आप एक ही त्रुटि मिलती हैं -:

भले ही आप अपने get लगेगा की तरह अपने खुद के समर्थन चर का इस्तेमाल किया।

हम्म ... अपने प्रश्न पढ़ अधिक ध्यान से शायद आप वास्तव में अपने वर्ग के भीतर से सीधे समर्थन चर संशोधित करने के लिए मतलब है: -

myOrigin.X = 10; 

हाँ कि हो सकता है कि तुम क्या आवश्यकता होगी।

0

मुझे लगता है कि यहाँ पकड़ है कि आप बयान में वस्तु की उप-मान निर्दिष्ट करने के बजाय की कोशिश कर रहे है ऑब्जेक्ट को स्वयं असाइन करना। इस मामले में आपको संपूर्ण प्वाइंट ऑब्जेक्ट असाइन करने की आवश्यकता है क्योंकि संपत्ति का प्रकार बिंदु है।

Point newOrigin = new Point(10, 10); 
Origin = newOrigin; 

आशा मैं वहाँ भावना बनाया

+2

महत्वपूर्ण बिंदु यह है कि प्वाइंट एक संरचना (वैल्यूटाइप) है। यदि यह एक वर्ग (ऑब्जेक्ट) था तो मूल कोड काम करेगा। –

+0

Correctamundo - यह एक अच्छा साक्षात्कार सवाल हो सकता है। – MSIL

+0

@ हंसकेस्टिंग: यदि 'प्वाइंट' एक म्यूटेबल क्लास प्रकार था, तो मूल कोड संपत्ति 'उत्पत्ति' द्वारा लौटाई गई वस्तु में फ़ील्ड या प्रॉपर्टी 'एक्स' सेट करेगा। मुझे विश्वास करने का कोई कारण नहीं दिखता है कि 'मूल' संपत्ति वाले ऑब्जेक्ट पर वांछित प्रभाव होगा। कुछ फ्रेमवर्क कक्षाओं में गुण होते हैं जो अपने राज्य को नए उत्परिवर्तनीय वर्ग के उदाहरणों में प्रतिलिपि बनाते हैं और उन्हें वापस कर देते हैं। इस तरह के डिज़ाइन में 'thing1.Origin = thing2.Origin;' जैसे कोड को अनुमति देने का लाभ होता है, ऑब्जेक्ट की उत्पत्ति की स्थिति को दूसरे के मिलान के लिए सेट करने के लिए, लेकिन यह 'thing1.Origin.X + = जैसे कोड के बारे में चेतावनी नहीं दे सकता है। 4; '। – supercat

0

समस्या यह है कि आप ढेर और मूल्य पर स्थित एक मूल्य को इंगित वापस orignal संपत्ति को relfected नहीं किया जाएगा, ताकि सी # आप एक वापस जाने के लिए अनुमति नहीं देता है एक मूल्य प्रकार के संदर्भ में। मुझे लगता है कि आप उत्पत्ति संपत्ति को हटाकर इसे हल कर सकते हैं और इसके बजाय सार्वजनिक दायर का उपयोग कर सकते हैं, हां, मुझे पता है कि यह एक अच्छा समाधान नहीं है। दूसरा समाधान प्वाइंट का उपयोग नहीं करना है, और इसके बजाय ऑब्जेक्ट के रूप में अपना खुद का प्वाइंट प्रकार बनाएं।

+0

यदि 'प्वाइंट' किसी संदर्भ प्रकार का सदस्य है तो यह स्टैक पर नहीं होगा, यह ऑब्जेक्ट की स्मृति में ढेर पर होगा। –

4

अब तक आप पहले ही जानते हैं कि त्रुटि का स्रोत क्या है। यदि कोई कन्स्ट्रक्टर आपकी संपत्ति लेने के लिए अधिभार के साथ मौजूद नहीं है (इस मामले में X), तो आप ऑब्जेक्ट प्रारंभकर्ता (जो दृश्यों के पीछे सभी जादू करेंगे) का उपयोग कर सकते हैं। ऐसा नहीं है कि आप अपने structs अपरिवर्तनीय, लेकिन सिर्फ अतिरिक्त जानकारी देने नहीं कर की जरूरत है:

struct Point 
{ 
    public int X { get; set; } 
    public int Y { get; set; } 
} 

class MyClass 
{ 
    public Point Origin { get; set; } 
} 

MyClass c = new MyClass(); 
c.Origin.X = 23; //fails. 

//but you could do: 
c.Origin = new Point { X = 23, Y = c.Origin.Y }; //though you are invoking default constructor 

//instead of 
c.Origin = new Point(23, c.Origin.Y); //in case there is no constructor like this. 

यह संभव है क्योंकि पर्दे के पीछे होता है:

Point tmp = new Point(); 
tmp.X = 23; 
tmp.Y = Origin.Y; 
c.Origin = tmp; 

यह करने के लिए एक बहुत ही अजीब बात की तरह लग रहा करो, बिल्कुल अनुशंसित नहीं है। बस एक वैकल्पिक तरीका सूचीबद्ध करें। करने का बेहतर तरीका संरचना को अपरिवर्तनीय बनाना और उचित कन्स्ट्रक्टर प्रदान करना है।

+2

क्या वह 'Origin.Y' के मान को मिटा नहीं देगा? 'प्वाइंट' प्रकार की संपत्ति को देखते हुए, मुझे लगता है कि 'एक्स' को बदलने का बेवकूफ तरीका' var temp = thing.Origin होगा; temp.X = 23; बात.ऑर्गिन = अस्थायी; '।बेवकूफ दृष्टिकोण का लाभ यह है कि इसे उन सदस्यों का उल्लेख नहीं करना पड़ता है जो इसे संशोधित नहीं करना चाहते हैं, एक सुविधा जो केवल संभव है क्योंकि 'प्वाइंट' उत्परिवर्तनीय है। मैं दर्शन में परेशान हूं जो कहता है कि क्योंकि कंपाइलर 'Origin.X = 23' की अनुमति नहीं दे सकता है, 'किसी को' Origin.X = new Point (23, Origin.Y) जैसे कोड की आवश्यकता के लिए एक संरचना तैयार करनी चाहिए; ' । उत्तरार्द्ध वास्तव में मेरे लिए मुश्किल लगता है। – supercat

+0

@supercat ओह हाँ, अनदेखा है कि! मैं इसे संपादित कर दूंगा – nawfal

+0

@supercat यह पहली बार है जब मैं आपके बिंदु के बारे में सोच रहा हूं, ** बहुत समझ में आता है! ** क्या आपके पास इसका सामना करने के लिए वैकल्पिक पैटर्न/डिज़ाइन विचार है? यह आसान हो गया था कि सी # डिफ़ॉल्ट रूप से संरचना के लिए डिफ़ॉल्ट कन्स्ट्रक्टर प्रदान नहीं किया गया था (उस स्थिति में मुझे कड़ाई से विशिष्ट कन्स्ट्रक्टर को 'एक्स' और' वाई 'दोनों को पारित करना होगा)। अब यह उस बिंदु को खो देता है जब कोई 'प्वाइंट पी = नया प्वाइंट() 'कर सकता है। मुझे पता है कि इसकी संरचना के लिए वास्तव में क्यों जरूरी है, इसलिए सोचने में कोई बात नहीं है। लेकिन क्या आपके पास 'X' जैसी एक संपत्ति को अपडेट करने का अच्छा विचार है? – nawfal

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