एक कॉन्स्टेबल ऐरे को डिक्लेयर करें


457

क्या निम्नलिखित के समान कुछ लिखना संभव है?

public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

स्थैतिक का उपयोग किया जा सकता है, सार्वजनिक स्थैतिक स्ट्रिंग [] टाइटल = नई स्ट्रिंग [] {"जर्मन", "स्पेनिश"};
रे

जवाबों:


690

हां, लेकिन आपको इसके readonlyबजाय इसे घोषित करने की आवश्यकता है const:

public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

कारण यह है कि constकेवल उसी फ़ील्ड पर लागू किया जा सकता है जिसका मूल्य संकलन-समय पर जाना जाता है। आपके द्वारा दिखाया गया सरणी आरंभीकरण C # में एक स्थिर अभिव्यक्ति नहीं है, इसलिए यह एक संकलक त्रुटि पैदा करता है।

यह घोषित करना readonlyउस समस्या को हल करता है क्योंकि मूल्य को रन-टाइम तक आरंभीकृत नहीं किया जाता है (हालांकि यह पहली बार शुरू होने की गारंटी है कि सरणी का उपयोग किया जाता है)।

यह इस बात पर निर्भर करता है कि आप आखिरकार क्या हासिल करना चाहते हैं, आप एक एनम की घोषणा करने पर भी विचार कर सकते हैं:

public enum Titles { German, Spanish, Corrects, Wrongs };

115
ध्यान दें कि यहाँ सरणी बिल्कुल नहीं है, ज़ाहिर है; टाइटल [2] = "वेल्श"; रनटाइम पर ठीक काम करेगा
मार्क ग्रेवेल

46
आप शायद इसे भी स्थैतिक चाहते हैं
tymtam

4
एक विधि निकाय में "कॉन्स्ट" ऐरे की घोषणा करने के बारे में, कक्षा एक में नहीं?
सरहियो

19
डाउन वोट के लिए क्षमा करें, लेकिन स्थैतिक का अर्थ स्थैतिक भी है। सरणी को केवल पढ़ने के रूप में घोषित करना वर्कअराउंड के करीब नहीं है। readonly staticअनुरोधित शब्दार्थ का कोई सदृश होना आवश्यक है।
एंटोन

3
@ एटन, क्या आपने और आपके "अनुयायियों" ने नीचता को दूर किया है? मेरे staticलिए इसे काम करने की आवश्यकता नहीं है, यह सिर्फ Titlesउदाहरण के बिना संदर्भ की संभावना को जोड़ता है , लेकिन विभिन्न उदाहरणों के लिए मूल्य बदलने की संभावना को दूर करता है (उदाहरण के लिए आप पैरामीटर के साथ निर्माता हो सकते हैं, जिसके आधार पर आप उस readonlyफ़ील्ड के मूल्य को बदल सकते हैं )।
सिनट्रैट

57

आप सरणी को घोषित कर सकते हैं readonly, लेकिन ध्यान रखें कि आप readonlyसरणी के तत्व को बदल सकते हैं ।

public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";

कोम द्वारा सुझाए गए, या IList के रूप में, एनम का उपयोग करने पर विचार करें।

public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();

31
.NET 4.5 और उच्चतर में आप सूची को IList <string> के बजाय IReadOnlyList <string> के रूप में घोषित कर सकते हैं।
ग्रेज़गोरज़ स्मुल्को

बस स्पष्ट होने के लिए, आप अभी भी एक IReadOnlyList में मूल्यों को बदल सकते हैं (बस तत्वों को जोड़ या हटा नहीं सकते हैं)। लेकिन हाँ, इसे एक IReadOnlyList के रूप में घोषित करना एक IList से बेहतर होगा।
केविनविक्टर

सवाल यह constनहीं है readonly...
Yousha Aleayoub

50

आप एक 'कॉन्स्ट' एरे नहीं बना सकते क्योंकि एरे ऑब्जेक्ट्स हैं और केवल रनटाइम पर बनाए जा सकते हैं और कॉन्सटेबल इकाइयाँ संकलन समय पर हल हो जाती हैं।

इसके बजाय आप क्या कर सकते हैं अपने सरणी को "आसानी से" घोषित करें। यह उसी तरह का प्रभाव है जैसा कि कॉन्स्टिट को छोड़कर रनटाइम पर सेट किया जा सकता है। यह केवल एक बार ही सेट किया जा सकता है और इसके बाद एक पठनीय (यानी कास्ट) मान है।


2
यह पोस्ट इस बात पर प्रकाश
डालती है

1
एक निरंतर सरणी घोषित करना संभव है; समस्या इसे एक निरंतर मूल्य के साथ आरंभ कर रही है। एकमात्र कार्यशील उदाहरण जो दिमाग में आता है, const int[] a = null;जो बहुत उपयोगी नहीं है, लेकिन वास्तव में एक सरणी का एक उदाहरण है।
वाल्ड्रम्पस

यह केवल सही उत्तर है।
यौषा अलायबॉब

17

C # 6 के बाद से आप इसे लिख सकते हैं:

public static string[] Titles => new string[] { "German", "Spanish", "Corrects", "Wrongs" };

इन्हें भी देखें: C #: द न्यू एंड इम्प्रूव्ड C # 6.0 (विशेषकर अध्याय "एक्सप्रेशन बोडिड फंक्शंस एंड प्रॉपर्टीज़")

यह केवल-पढ़ने के लिए स्थिर संपत्ति बना देगा, लेकिन यह अभी भी आपको दी गई सरणी की सामग्री को बदलने की अनुमति देगा, लेकिन जब आप संपत्ति को फिर से कॉल करते हैं, तो आपको फिर से मूल, अनलेल्ड सरणी मिल जाएगी।

स्पष्टीकरण के लिए, यह कोड समान है (या वास्तव में इसके लिए एक आशुलिपि):

public static string[] Titles
{
    get { return new string[] { "German", "Spanish", "Corrects", "Wrongs" }; }
}

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

यदि आप एक अपरिवर्तनीय सरणी (या सूची) रखना चाहते हैं, तो आप इसका उपयोग भी कर सकते हैं:

public static IReadOnlyList<string> Titles { get; } = new string[] { "German", "Spanish", "Corrects", "Wrongs" };

लेकिन, इसमें अभी भी परिवर्तनों का जोखिम है, क्योंकि आप अभी भी इसे एक स्ट्रिंग में वापस डाल सकते हैं [और सामग्री को बदल सकते हैं, जैसे कि:

((string[]) Titles)[1] = "French";

1
इस मामले में क्षेत्र के बजाय संपत्ति का उपयोग करने का क्या लाभ है?
निकोलय.न्याकेंको

2
प्रत्येक कॉल पर एक फ़ील्ड एक नई वस्तु नहीं लौटा सकती है। एक संपत्ति मूल रूप से "भेष में कार्य" है।
mjepson

1
यदि आप अंतिम विकल्प की बात कर रहे हैं, तो यह एक क्षेत्र या एक संपत्ति दोनों का उपयोग करके किया जा सकता है, लेकिन चूंकि यह सार्वजनिक है, इसलिए मैं एक संपत्ति पसंद करता हूं। मैं प्रॉपर्टी की शुरुआत के बाद से कभी भी सार्वजनिक क्षेत्र का उपयोग नहीं करता।
mjepson 10:

1
1 दृष्टिकोण के लिए एक और नकारात्मक पहलू है: Titles[0]उदाहरण के लिए , यदि आप असाइन करते हैं तो आपको एक संकलन त्रुटि नहीं मिलेगी - वास्तव में, असाइनमेंट प्रयास को चुपचाप अनदेखा कर दिया जाता है। हर बार सरणी को फिर से बनाने की अक्षमता के साथ संयुक्त, मुझे आश्चर्य है कि क्या यह दृष्टिकोण भी दिखाने योग्य है। इसके विपरीत, दूसरा दृष्टिकोण कुशल है, और आपको अपरिवर्तनीयता को हराने के लिए अपने रास्ते से बाहर जाना होगा।
mklement0

6

यदि आप IReadOnlyList इंटरफ़ेस के पीछे एक सरणी घोषित करते हैं, तो आपको निरंतर मान के साथ एक निरंतर सरणी मिलती है जो रनटाइम पर घोषित की जाती है:

public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };

.NET 4.5 और उच्चतर में उपलब्ध है।


6

एक .NET फ्रेमवर्क v4.5 + समाधान जो tdbeckett के उत्तर में सुधार करता है :

using System.Collections.ObjectModel;

// ...

public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>(
  new string[] { "German", "Spanish", "Corrects", "Wrongs" }
);

नोट: यह देखते हुए कि संग्रह वैचारिक रूप से स्थिर है, वर्ग स्तर staticपर इसे घोषित करने के लिए इसे बनाने के लिए समझ में आ सकता है।

उपरोक्त:

  • सरणी के साथ एक बार संपत्ति के अंतर्निहित बैकिंग क्षेत्र को आरम्भ करता है।

    • ध्यान दें { get; }- अर्थात, केवल एक संपत्ति पाने वाला घोषित करना - वह है जो संपत्ति को केवल अनुमानित रूप से केवल-पढ़ने के लिए बनाता है ( वास्तव में एक सिंटैक्स त्रुटि के readonlyसाथ संयोजन करने की कोशिश कर रहा है { get; })।

    • वैकल्पिक रूप से, आप सिर्फ छोड़ सकते हैं { get; }और एक संपत्ति के बजाय readonlyएक फ़ील्ड बनाने के लिए जोड़ सकते हैं, जैसा कि सवाल है, लेकिन सार्वजनिक डेटा सदस्यों को फ़ील्ड के बजाय गुणों के रूप में उजागर करना एक अच्छी आदत है।

  • एक सरणी बनाता है- संरचना की तरह ( अनुक्रमणित पहुंच की अनुमति देता है ) जो वास्तव में और मजबूत रूप से केवल पढ़ने योग्य है (वैचारिक रूप से स्थिर, एक बार बनाया गया), दोनों सम्मान के साथ:

    • समग्र रूप में संग्रह को रोकना (जैसे तत्वों को निकालना या जोड़ना, या चर को एक नया संग्रह निर्दिष्ट करके)।
    • व्यक्तिगत तत्वों के संशोधन को रोकना
      (यहां तक कि अप्रत्यक्ष संशोधन संभव नहीं है - एक साथ विपरीत IReadOnlyList<T>समाधान है, जहां एक (string[])डाली तत्वों के लिए लेखन पहुँच हासिल करने के लिए इस्तेमाल किया जा सकता है, के रूप में दिखाया गया है mjepsen के मददगार जवाब
      एक ही जोखिम पर लागू होता है इंटरफेस है, जो, नाम में समानता के बावजूद करने के लिए वर्ग , भी समर्थन नहीं करता है अनुक्रमित पहुँच , यह मूल रूप प्रदान करने पहुँच सरणी की तरह के लिए अनुपयुक्त बना।)IReadOnlyCollection<T> ReadOnlyCollection

1
@mortb: दुर्भाग्य से, IReadOnlyCollectionअनुक्रमित पहुंच का समर्थन नहीं करता है, इसलिए इसका उपयोग यहां नहीं किया जा सकता है। इसके अतिरिक्त, जैसे IReadOnlyList(जिसमें अनुक्रमणित पहुंच है) यह वापस जोड़कर तत्व हेरफेर करने के लिए अतिसंवेदनशील है string[]। दूसरे शब्दों में: ReadOnlyCollection(जो आप एक स्ट्रिंग सरणी नहीं कर सकते हैं) सबसे मजबूत समाधान है। एक गेटर का उपयोग नहीं करना एक विकल्प है (और मैंने उस नोट का जवाब अपडेट किया है), लेकिन सार्वजनिक डेटा के साथ संपत्ति के साथ रहना बेहतर है।
mklement0

5

मेरी जरूरतों के लिए, मैं staticअसंभव के बजाय सरणी को परिभाषित करता हूं constऔर यह काम करता है: public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };


1
बस constओपी उदाहरण से हटाना भी काम करता है, लेकिन यह (या आपका जवाब) दोनों को बदलने की अनुमति देता है: Titlesउदाहरण और कोई भी मूल्य। तो इस उत्तर में क्या बात है?
सिनट्रैट

@Sinatr, मैंने 3 साल पहले इसका उत्तर दिया था, जब मैंने C # में काम करना शुरू किया था। मैंने इसे छोड़ दिया, अब मैं जावा दुनिया में हूं। शायद मैं जोड़ना भूल गयाreadonly
ALZ

दूसरी सोचा के बाद, आपका जवाब सीधा है कैसे ओपी कोड काम कर रहे बनाने के लिए किसी भी बिना, const/ readonly, विचार बस यह काम कर रहा बनाने (जैसे यदि constएक वाक्य रचना गलती थी)। कुछ लोगों के लिए यह एक मूल्यवान उत्तर लगता है (शायद उन्होंने constगलती से भी उपयोग करने की कोशिश की ?)।
सिनटार

5

आप एक अलग तरीका अपना सकते हैं: अपने सरणी का प्रतिनिधित्व करने के लिए एक निरंतर स्ट्रिंग को परिभाषित करें और फिर आवश्यकता पड़ने पर स्ट्रिंग को एक सरणी में विभाजित करें, जैसे

const string DefaultDistances = "5,10,15,20,25,30,40,50";
public static readonly string[] distances = DefaultDistances.Split(',');

यह दृष्टिकोण आपको एक निरंतरता देता है जिसे कॉन्फ़िगरेशन में संग्रहीत किया जा सकता है और जरूरत पड़ने पर एक सरणी में परिवर्तित किया जा सकता है।


8
मुझे लगता है कि कॉस्ट को परिभाषित करके किए गए किसी भी लाभ को विभाजित करने की लागत दूर है। लेकिन बॉक्स के बाहर एक अद्वितीय दृष्टिकोण और सोच के लिए +1! ;)
रेडडरज़

मैं उसी समाधान को पोस्ट करने वाला था और फिर यह देखा, कठोर और नकारात्मक टिप्पणियों के विपरीत, यह वास्तव में मेरे परिदृश्य के लिए एकदम सही था, जहां मुझे एक प्रस्ताव को एक प्रस्ताव पारित करने की आवश्यकता थी, और फिर मैंने विशेषता निर्माणकर्ता में मान को विभाजित किया मुझे क्या चाहिए और मेरे पास कोई कारण नहीं है कि प्रदर्शन लागत क्यों होगी क्योंकि प्रत्येक उदाहरण के लिए विशेषताएँ नहीं बनाई गई हैं।
कल्पेश पोपट

4

पूर्णता के लिए, अब हमारे पास अपने निपटान में ImmutableArrays भी है। यह वास्तव में अपरिवर्तनीय होना चाहिए:

public readonly static ImmutableArray<string> Tiles = ImmutableArray.Create(new[] { "German", "Spanish", "Corrects", "Wrongs" });

System.Collections.Immutable NuGet संदर्भ की आवश्यकता है

https://msdn.microsoft.com/en-us/library/mt452182(v=vs.111).aspx


3

यह वह तरीका है जो आप करना चाहते हैं:

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;

public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}

यह बहुत आसानी से एक सरणी के समान है।


8
आप बस ऐसा कर सकते हैं public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();; यदि आप इसे वैसे भी ReadOnlyCollection बनाते हैं, तो प्रत्येक पुनर्प्राप्ति पर सूची को फिर से बनाने की आवश्यकता नहीं है।
Nyerguds

3

यह एकमात्र सही उत्तर है। आप वर्तमान में ऐसा नहीं कर सकते।

अन्य सभी उत्तर स्थिर रीड-ओनली चर का उपयोग करने का सुझाव दे रहे हैं जो समान हैं , लेकिन स्थिर के समान नहीं हैं। असेंबली में एक निरंतर हार्ड कोडित होता है। एक स्थिर रीड ओनली वेरिएबल एक बार सेटल हो जाता है, शायद जैसा कि किसी ऑब्जेक्ट को इनिशियलाइज़ किया जाता है।

ये कभी-कभी विनिमेय होते हैं, लेकिन हमेशा नहीं।


2

मेरा मानना ​​है कि आप इसे केवल आसानी से पढ़ सकते हैं।


2

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


0

एक विकल्प के रूप में, एक आसानी से सरणी के साथ तत्वों-के-संशोधित-संशोधित मुद्दे के आसपास पाने के लिए, आप इसके बजाय एक स्थिर संपत्ति का उपयोग कर सकते हैं। (व्यक्तिगत तत्वों को अभी भी बदला जा सकता है, लेकिन ये परिवर्तन केवल सरणी की स्थानीय प्रति पर किए जाएंगे।)

public static string[] Titles 
{
    get
    {
        return new string[] { "German", "Spanish", "Corrects", "Wrongs"};
    }
}

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


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.