2010-09-07 21 views
12

क्या सी # एक चर को अनुमति देता है जिसे संशोधित नहीं किया जा सकता है? यह const की तरह है, लेकिन इसे घोषणा पर एक मान असाइन करने की बजाय, चर के पास कोई डिफ़ॉल्ट मान नहीं है, लेकिन केवल रनटाइम पर एक बार एक मान असाइन किया जा सकता है (संपादित करें: और संभवतः कन्स्ट्रक्टर से नहीं)। या यह संभव नहीं है?परिवर्तनीय को संशोधित नहीं किया जा सकता है

+12

भाषाई नाइटपिक: "एक चर जो संशोधित नहीं किया जा सकता" एक ऑक्सीमोरोन है। – LukeH

उत्तर

5

आप अपनी खुद की जेनेरिक क्लास बना सकते हैं जो इस कार्यक्षमता प्रदान करता है, लेकिन यह अधिक हो सकता है।

public class SetValueOnce<T> 
{ 
    public bool _set; 
    private T _value; 

    public SetValueOnce() 
    { 
     _value = default(T); 
     _set = false; 
    } 

    public SetValueOnce(T value) 
    { 
     _value = value; 
     _set = true; 
    } 

    public T Value 
    { 
     get 
     { 
      if(!_set) 
      throw new Exception("Value has not been set yet!"); 
      return _value; 
     { 
     set 
     { 
     if(_set) 
      throw new Exception("Value already set!"); 
     _value = value; 
     _set = true; 
     } 
    } 
} 
+0

आप कुछ उद्धरण चिह्न –

+0

@ लुइस को भूल गए हैं, अपडेट किया गया है, यह सिंटैक्स सही होना चाहिए, लेकिन मैंने उत्तर के हिस्से के रूप में सीधे कोड ब्लॉक के रूप में टाइप किया - मैं एसओ की सिफारिश नहीं करता एक कोड संपादक - एक चीज़ के लिए कोई स्रोत नियंत्रण एकीकरण :) –

+0

निष्पक्ष होने के लिए मैं इसे स्वीकार करता हूं क्योंकि यह मेरे प्रश्न में आवश्यकता को मान्य है .. भले ही मुझे वास्तव में सीके के उत्तर पसंद हैं और वास्तव में मुझे –

12

आप readonly वैरिएबल घोषित कर सकते हैं जिसे केवल निर्माता में या सीधे इसकी घोषणा के माध्यम से सेट किया जा सकता है।

+0

तो इसे एक निर्माता से होना चाहिए? –

+0

आप एक्सेस को प्रतिबंधित कर सकते हैं और केवल अपनी कक्षा के भीतर फ़ील्ड को सेट करने की अनुमति दे सकते हैं, लेकिन 'रीडोनली' और 'कॉन्स्ट' एकमात्र भाषा संरचनाएं हैं जो वास्तव में निर्माण या घोषणा के बाद मूल्य निर्धारित करने की अनुमति देती हैं। –

+1

हां, या तो इसके कन्स्ट्रक्टर या घोषणा के भीतर इनलाइन (लेकिन फिर एक कॉन्स की तरह)। इसके अलावा इसे केवल निर्माण समय पर ही निर्माता के भीतर होना चाहिए - इसका मतलब है कि कन्स्ट्रक्टर द्वारा बुलाए गए फ़ंक्शन के भीतर रीडोनली चर के मान को सेट करना संभव नहीं है। –

4

निश्चित रूप से। आप readonly उपयोग कर सकते हैं:

यानी .: public readonly int z;

यह केवल निर्माता के भीतर से संशोधित किया जा सकता।

MSDN से

:

आप केवल निम्नलिखित संदर्भों में एक केवल पढ़ने के लिए क्षेत्र के लिए एक मूल्य निर्दिष्ट कर सकते हैं:

जब चर घोषणा में आरंभ नहीं हो जाता उदाहरण के लिए,:

  • public readonly int y = 5;

  • उदाहरण के लिए, कक्षा टी के रचनाकारों में टोपी क्षेत्र घोषणा, या एक स्थैतिक क्षेत्र के लिए, कक्षा के स्थिर कन्स्ट्रक्टर में फ़ील्ड घोषणा शामिल है। ये एकमात्र संदर्भ भी हैं जिनमें रीडोनली फ़ील्ड को out या ref पैरामीटर के रूप में पास करने के लिए मान्य है।

यदि फिर भी आप एक संपत्ति है कि केवल वर्ग है कि यह बनाया भीतर बदला जा सकता है बनाना चाहते हैं, तो आप उपयोग कर सकते हैं निम्नलिखित:

public string SetInClass 
{ 
    get; 
    private set; 
} 

यह अनुमति देता है परिवर्तन वर्ग के भीतर किए जाने के लिए , लेकिन परिवर्तनीय कक्षा के बाहर से बदला नहीं जा सकता है।

1

आप एक पाठक चर को परिभाषित कर सकते हैं जो केवल ऑब्जेक्ट कन्स्ट्रक्टर में मूल्य निर्धारित हो सकता है। इसके बारे में यहाँ

पढ़ें: http://msdn.microsoft.com/en-us/library/acdd6hb7%28v=VS.100%29.aspx

1

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

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

5

आप एक कस्टम सेटर का उपयोग कर अपने स्वयं के रोल कर सकते हैं (लेकिन Object का उपयोग नहीं करते जब तक आप सही वर्ग चुनने के लिए):

private Object myObj = null; 
private Boolean myObjSet = false; 

public Object MyObj 
{ 
    get { return this.myObj; } 
    set 
    { 
     if (this.myObjSet) throw new InvalidOperationException("This value is read only"); 
     this.myObj = value; 
     this.myObjSet = true; 
    } 
} 

संपादित करें:

यह नहीं करता है ' कक्षा के आंतरिक द्वारा निजी क्षेत्र को बदला जा रहा है।

+1

@ केली, क्यों? यदि आप उपर्युक्त संपादन को देखते हैं तो यह कहता है कि यह संभवतः रचनाकार से निर्धारित नहीं होगा जो केवल पढ़ने के लिए नियम बनाता है! ओपी की आवश्यकताओं को देखते हुए मुझे वैध कार्यान्वयन की तरह दिखता है! – OneSHOT

+0

वाह महान विचार! –

+2

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

0

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

private myVariable = null; 
public object MyVariable 
{ 
    get { return myVariable; } 
    set { if(myVariable == null) myVariable = value; 
} 
23

हां, सी # में ऐसा करने के कई तरीके हैं।

सबसे पहले, "चर" क्या है? एक चर एक भंडारण स्थान है। स्थानीय चर, विधियों के औपचारिक पैरामीटर (और इंडेक्सर्स, कन्स्ट्रक्टर और इतने पर), स्थैतिक और आवृत्ति फ़ील्ड, सरणी तत्व और पॉइंटर डेरेंस सभी चर हैं।

कुछ चर "घोषित" के रूप में घोषित किया जा सकता है। एक "केवल पढ़ने योग्य" चर केवल एक बार बदला जा सकता है, या तो घोषणा में प्रारंभकर्ता द्वारा, या एक कन्स्ट्रक्टर में। केवल फ़ील्ड घोषणाएं ही पढ़ी जा सकती हैं; सी # उपयोगकर्ता द्वारा घोषित रीडोनली स्थानीय लोगों का समर्थन नहीं करता है।

केवल पढ़ने योग्य चर पर कुछ प्रतिबंध हैं जो यह सुनिश्चित करने में सहायता करते हैं कि सी # का सामान्य संचालन एक उत्परिवर्तन पेश नहीं करता है। इससे कुछ अप्रत्याशित परिणाम हो सकते हैं!

http://ericlippert.com/2008/05/14/mutating-readonly-structs/

जानकारी के लिए

देखें।

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

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

स्थानीय चर एक foreach बयान में घोषित भी प्रभावी ढंग से readonly है - कि लूप के माध्यम से हर बार परिवर्तनीय परिवर्तन मूल्य, लेकिन आप को इसके मूल्य को बदलने की अनुमति नहीं है।

रीडोनली औपचारिक पैरामीटर, सरणी तत्व या पॉइंटर अव्यवस्था बनाने का कोई तरीका नहीं है।

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

+1

की आवश्यकता है सी # के आंतरिक पर थोड़ा और समझाने के लिए +1 .. बहुत शिक्षित! – Arcturus

+0

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

+0

@ पॉल: लेकिन निश्चित रूप से वे * चर * नहीं हैं। स्थिरांक चर नहीं हैं क्योंकि * स्थिर * और * चर * * विरोध * हैं। (और आप यह कहना गलत हैं कि ValueType- व्युत्पन्न स्थानीय स्थिरांक हो सकते हैं। मैं आपको आश्वस्त करता हूं कि वे नहीं कर सकते हैं। मुझे संदेह है कि आप किसी अन्य भाषा के बारे में सोच रहे हैं; शायद सी ++।) –

1

एक similar question के बाद से हाल ही में @Ivan द्वारा कहा गया है, मुझे अभी तक किसी अन्य विधि का सुझाव एक सामान्य निर्माता के समर्थन के साथ कोड में किसी भी स्थान पर एक संपत्ति instanciate लिए, ज़ाहिर है, अधिक वास्तव में, करते हैं।

public class Immutable<T> { 
    public T Val { get; private set; } 
    public Immutable(T t) { 
     Val = t; 
    } 
} 

प्रयोग

var immutableInt1 = new Immutable<int>(3); // you can set only once 
immutableInt1.Val = 5; // compile error here: set inaccessible 
Console.WriteLine("value: " + immutableInt1.Val); 

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

इसके अलावा, मेरा मानना ​​है कि यदि आप उस प्रतिमान का पालन करना चाहते हैं तो आप सी # की बजाय एक कार्यात्मक भाषा का उपयोग करना बेहतर कर सकते हैं।

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