C # में किसी फ़ील्ड को 'readonly` के रूप में चिह्नित करने के क्या लाभ हैं?


295

केवल पढ़ने के लिए घोषित सदस्य चर होने के क्या लाभ हैं? क्या यह सिर्फ कक्षा के जीवनचक्र के दौरान किसी के मूल्य को बदलने के खिलाफ है या किसी भी गति या दक्षता में सुधार के परिणामस्वरूप इस कीवर्ड का उपयोग करता है?


8
अच्छा बाहरी जवाब: dotnetperls.com/readonly
OneWorld

3
दिलचस्प। यह अनिवार्य रूप से इस जावा प्रश्न का C # समतुल्य है stackoverflow.com/questions/137868// यहाँ चर्चा बहुत कम गर्म है, हालांकि ... हम्म ...
RAY

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

2
प्रदर्शन के दंड पर अधिक: codeblog.jonskeet.uk/2014/07/16/…
CAD

जवाबों:


171

readonlyकीवर्ड एक सदस्य चर एक निरंतर घोषित करने के लिए प्रयोग किया जाता है, लेकिन मूल्य रनटाइम पर गणना की जा सकती है। यह constसंशोधक के साथ घोषित निरंतर से भिन्न होता है , जिसका संकलन समय पर इसका मान होना चाहिए। readonlyआप का उपयोग करके क्षेत्र के मूल्य को घोषणा में या वस्तु के निर्माता में सेट कर सकते हैं कि क्षेत्र का सदस्य है।

यदि आप बाह्य DLL को फिर से जोड़ना चाहते हैं, तो भी इसका उपयोग करें जो स्थिरांक को संदर्भित करता है (क्योंकि यह संकलन समय पर प्रतिस्थापित हो जाता है)।


193

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

हालाँकि "वाचली" अन्य प्रकार के रीड-ओनली शब्दार्थों से बहुत भिन्न है क्योंकि यह CLR द्वारा रनटाइम पर लागू किया जाता है। आसानी से पढ़ने वाला कीवर्ड .initonly के लिए संकलित करता है जो CLR द्वारा सत्यापित होता है।

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

यहाँ अपरिवर्तनीयता के एक लाभ के बारे में एक अच्छी प्रविष्टि है: थ्रेडिंग


6
यदि आप इसे पढ़ते हैं, तो stackoverflow.com/questions/9860595/… केवल पढ़ने के लिए सदस्य को संशोधित किया जा सकता है और .net द्वारा असंगत व्यवहारकर्ता की तरह दिखता है
आकाश काव

69

उपयोग करने के लिए कोई स्पष्ट प्रदर्शन लाभ नहीं हैं readonly, कम से कम कोई भी नहीं जिसे मैंने कभी भी कहीं भी देखा है। यह जैसा आपने सुझाया है, वैसा ही करने के लिए, जैसा कि इसे शुरू में संशोधित किया गया है, इसे रोकने के लिए है।

इसलिए यह फायदेमंद है कि यह आपको अधिक मजबूत, अधिक पठनीय कोड लिखने में मदद करता है। इस तरह की चीजों का वास्तविक लाभ तब मिलता है जब आप किसी टीम में या रखरखाव के लिए काम कर रहे होते हैं। readonlyकोड में उस चर के उपयोग के लिए एक अनुबंध डालने के लिए कुछ के रूप में घोषणा करना । जैसे अन्य कीवर्ड के रूप में एक ही तरह से प्रलेखन जोड़ने के रूप में समझें internalया private, तुम कह रहे हो "इस चर initialisation के बाद संशोधित नहीं किया जाना चाहिए", और आप इसके अलावा रहे हैं लागू करने यह।

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


और ओटोह भाषा को दर्शाता है। हालाँकि, आपके लाभ कथन से इनकार नहीं किया जा रहा है।
dkretz

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

7
यह जवाब और चर्चा वास्तव में मेरी राय में सबसे अच्छा जवाब है +1
जेफ मार्टिन

@Xiaofu: आपने मुझे आसानी से हाहा सुंदर व्याख्या के विचार के बारे में निरंतर बना दिया है कि इस दुनिया में कोई भी व्यक्ति के दिमाग को एक समझ नहीं बता सकता है
शिक्षार्थी

यानी आप अपने कोड में इस बात के इरादे से रह रहे हैं कि यह मूल्य किसी भी समय नहीं बदलना चाहिए।
एंडेज़

51

इसे बहुत व्यावहारिक शब्दों में कहें:

यदि आप dll A में एक const का उपयोग करते हैं और उस const को dll B संदर्भ देते हैं, तो उस const का मान dll B में संकलित किया जाएगा। यदि आप उस const के लिए एक नए मान के साथ dll A को फिर से परिभाषित करते हैं, तो dll B अभी भी मूल मान का उपयोग कर रहा होगा।

यदि आप dll A में एक readonly का उपयोग करते हैं और उस B को संदर्भित करते हैं जो आसानी से पढ़ता है, तो उस readonly को हमेशा रनटाइम तक देखा जाएगा। इसका मतलब है कि यदि आप उस डी के लिए एक नए मान के साथ dll ए को फिर से परिभाषित करते हैं, तो dll B उस नए मान का उपयोग करेगा।


4
अंतर को समझने के लिए यह एक अच्छा व्यावहारिक उदाहरण है। धन्यवाद।
श्योजू

दूसरी ओर, constप्रदर्शन में वृद्धि हो सकती है readonly। यहाँ कोड के साथ थोड़ा गहरा स्पष्टीकरण दिया गया है: dotnetperls.com/readonly
Dio Phung

2
मुझे लगता है कि सबसे बड़ा व्यावहारिक शब्द इस उत्तर से गायब है: मूल्यों को स्टोर करने की क्षमता readonlyखेतों में रनटाइम पर गणना की जाती है । आप एक new object();को स्टोर नहीं कर सकते हैं constऔर यह समझ में आता है क्योंकि आप गैर-मूल्य वाली चीजों को सेंक नहीं सकते हैं जैसे कि पहचान बदलने के बाद संकलन समय के दौरान अन्य विधानसभाओं में संदर्भ।
बिंकी जू

14

एक संभावित मामला है जहां कंपाइलर रीडऑनली कीवर्ड की उपस्थिति के आधार पर एक प्रदर्शन अनुकूलन कर सकता है।

यह केवल तभी लागू होता है जब रीडोनॉली फ़ील्ड को स्थिर के रूप में भी चिह्नित किया जाता है । उस स्थिति में, JIT कंपाइलर मान सकता है कि यह स्थिर क्षेत्र कभी नहीं बदलेगा। वर्ग के तरीकों का संकलन करते समय जेआईटी संकलक इसे ध्यान में रख सकता है।

विशिष्ट उदाहरण: आपकी कक्षा में एक स्थैतिक आसानी से IsDebugLoggingEnabled फ़ील्ड हो सकती है जो कि कंस्ट्रक्टर में आरंभीकृत की जाती है (जैसे कॉन्फ़िगरेशन फ़ाइल पर आधारित)। एक बार वास्तविक तरीके JIT संकलित हो जाने के बाद, डिबगर लॉगिंग सक्षम नहीं होने पर कंपाइलर कोड के पूरे हिस्सों को ommit कर सकता है।

मैंने जांच नहीं की है कि क्या यह अनुकूलन वास्तव में जेआईटी कंपाइलर के वर्तमान संस्करण में लागू किया गया है, इसलिए यह सिर्फ अटकलें हैं।


क्या इसके लिए कोई स्रोत है?
सेदत कपपनोग्लू

4
वर्तमान जेआईटी संकलक वास्तव में इसे लागू करता है, और सीएलआर 3.5 के बाद से है। github.com/dotnet/coreclr/issues/1079
mirhagk

साधारण क्षेत्रों के लिए पठनीय क्षेत्रों पर कोई अनुकूलन नहीं किया जा सकता है क्योंकि पठनीय क्षेत्र आसानी से पढ़े-लिखे नहीं होते हैं। वे केवल एक संकलक संकेत हैं जो अधिकांश संकलक सम्मान करते हैं और आसानी से पठनीय क्षेत्रों के मूल्यों को प्रतिबिंब के माध्यम से आसानी से ओवरराइट किया जा सकता है (हालांकि आंशिक रूप से विश्वसनीय कोड में नहीं)।
क्रिस्टोफ

9

ध्यान रखें कि पठनीयता केवल मान पर ही लागू होती है, इसलिए यदि आप किसी संदर्भ प्रकार का उपयोग आसानी से कर रहे हैं तो केवल संदर्भ को परिवर्तन से बचाता है। उदाहरण की स्थिति को आसानी से संरक्षित नहीं किया जाता है।


4

मत भूलो कि readonlyकिसी भी निर्माणकर्ताओं के उपयोग से बाहर खेतों को स्थापित करने के लिए एक समाधान हैout पार्म्स ।

थोड़ा गन्दा लेकिन:

private readonly int _someNumber;
private readonly string _someText;

public MyClass(int someNumber) : this(data, null)
{ }

public MyClass(int someNumber, string someText)
{
    Initialise(out _someNumber, someNumber, out _someText, someText);
}

private void Initialise(out int _someNumber, int someNumber, out string _someText, string someText)
{
    //some logic
}

आगे की चर्चा यहां: http://www.adamjamesnaylor.com/2013/01/23/Setting-Readonly-Fields-From-Chained-Constructors.aspx


4
खेतों को अभी भी कंस्ट्रक्टर में सौंपा गया है .. कोई "आसपास नहीं" है। इससे कोई फर्क नहीं पड़ता कि मान एकल अभिव्यक्तियों से हैं, एक विघटित जटिल प्रकार से, या संदर्भ के शब्दार्थ द्वारा कॉल के माध्यम से असाइन किए गए हैं out..
user2864740

यह प्रश्न का उत्तर देने का प्रयास भी नहीं करता है।
शेरिदान

2

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

https://codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/


3
ध्यान दें कि यदि फ़ील्ड एक प्रकार का है जो readonly structC # 7.2 में है, तो फ़ील्ड को गैर-पठनीय बनाने का लाभ चला जाता है।
जॉन स्कीट

1

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


1

इस प्रश्न का उत्तर देने के लिए एक मूल पहलू जोड़ना:

setऑपरेटर को छोड़ कर गुणों को आसानी से व्यक्त किया जा सकता है । इसलिए ज्यादातर मामलों में आपको readonlyसंपत्तियों में कीवर्ड जोड़ने की आवश्यकता नहीं होगी :

public int Foo { get; }  // a readonly property

इसके विपरीत: फ़ील्ड readonlyको समान प्रभाव प्राप्त करने के लिए कीवर्ड की आवश्यकता होती है:

public readonly int Foo; // a readonly field

तो, एक क्षेत्र के रूप में चिह्नित करने का एक फायदा readonlyयह हो सकता है कि setऑपरेटर के बिना एक संपत्ति के रूप में एक समान लेखन संरक्षण स्तर को प्राप्त किया जा सकता है - किसी भी कारण से, यदि वांछित है, तो संपत्ति को क्षेत्र को बदलने के बिना।


क्या 2 के बीच व्यवहार में अंतर है?
पेट्रोसम

0

निजी पठनीय सरणियों से सावधान रहें। यदि ये एक ग्राहक को एक वस्तु के रूप में उजागर करते हैं (आप COM इंटरॉप के लिए ऐसा कर सकते हैं जैसा कि मैंने किया था) ग्राहक सरणी मानों में हेरफेर कर सकता है। ऑब्जेक्ट के रूप में एक सरणी वापस करते समय क्लोन () विधि का उपयोग करें।


20
नहीं; ReadOnlyCollection<T>एक सरणी के बजाय बेनकाब ।
एसएलकेएस

यह एक टिप्पणी नहीं एक उत्तर होनी चाहिए क्योंकि यह प्रश्न का कोई उत्तर प्रदान नहीं करता है ...
पीटर

मजेदार रूप से पर्याप्त, मैंने इस तरह की बात को एक जवाब के रूप में रखने के लिए कहा, बजाय एक टिप्पणी के जब मैंने पिछले हफ्ते एक और पोस्ट पर किया था।
काइल बरन

2013 तक, आप उपयोग कर सकते हैं ImmutableArray<T>, जो एक इंटरफ़ेस ( IReadOnlyList<T>) या एक वर्ग ( ReadOnlyCollection) में लपेटकर बॉक्सिंग से बचा जाता है । इसमें मूल सरणियों की तुलना में प्रदर्शन है: blogs.msdn.microsoft.com/dotnet/2013/06/24/…
चार्ल्स टेलर

0

WPF में एक प्रदर्शन लाभ हो सकता है, क्योंकि यह महंगे DependencyProperties की आवश्यकता को हटा देता है। यह संग्रह के साथ विशेष रूप से उपयोगी हो सकता है


0

आसानी से मार्किंग के उपयोग का एक और दिलचस्प हिस्सा सिंगलटन में इनिशियलाइज़ेशन से क्षेत्र की रक्षा करना हो सकता है।

उदाहरण के लिए csharpindepth से कोड में :

public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());

    public static Singleton Instance { get { return lazy.Value; } }

    private Singleton()
    {
    }
}

फ़ील्ड सिंग्लटन को दो बार आरंभीकृत होने से बचाने के लिए आसानी से छोटी भूमिका निभाता है। एक अन्य विवरण यह है कि उल्लेखित परिदृश्य के लिए आप कॉन्स्ट का उपयोग नहीं कर सकते क्योंकि कॉन्सल कंपाइल समय के दौरान निर्माण करते हैं, लेकिन सिंगलटन रन टाइम पर निर्माण करता है।


0

readonlyघोषणा पर आरंभीकृत किया जा सकता है या केवल कंस्ट्रक्टर से इसका मूल्य प्राप्त कर सकते हैं। इसके विपरीत constइसे एक ही समय में शुरू और घोषित किया जाना है। readonly सब कुछ const है, प्लस निर्माण आरंभीकरण

कोड https://repl.it/HvRU/1

using System;

class MainClass {
    public static void Main (string[] args) {

        Console.WriteLine(new Test().c);
        Console.WriteLine(new Test("Constructor").c);
        Console.WriteLine(new Test().ChangeC()); //Error A readonly field 
        // `MainClass.Test.c' cannot be assigned to (except in a constructor or a 
        // variable initializer)
    }


    public class Test {
        public readonly string c = "Hello World";
        public Test() {

        }

        public Test(string val) {
          c = val;
        }

        public string ChangeC() {
            c = "Method";
            return c ;
        }
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.