Відповіді:
Так, але вам потрібно оголосити це readonlyзамість const:
public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
Причина в тому, що constйого можна застосувати лише до поля, значення якого відомо під час компіляції. Ініціалізатор масиву, який ви показали, не є постійним виразом у C #, тому він створює помилку компілятора.
Декларуючи це, readonlyвирішується ця проблема, оскільки значення не ініціалізується до часу виконання (хоча гарантовано, що воно ініціалізується до першого використання масиву).
Залежно від того, що ви, нарешті, хочете досягти, ви також можете розглянути питання про декларацію про перерахунок:
public enum Titles { German, Spanish, Corrects, Wrongs };
readonly staticмати будь-яку схожість із запитуваною семантикою.
staticне потрібно, щоб він працював, він просто додає можливість посилання, Titlesне маючи примірника, але видаляє можливість змінити значення для різних екземплярів (наприклад, ви можете мати конструктор з параметром залежно від того, що ви змінюєте значення цього readonlyполя).
Ви можете оголосити масив як readonly, але майте на увазі, що ви можете змінити елемент readonlyмасиву.
public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";
Подумайте про використання enum, як запропонував Коді, або IList.
public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
constНЕ readonly...
Ви не можете створити масив 'const', оскільки масиви є об'єктами, і їх можна створювати лише під час виконання, а об'єкти const вирішуються під час компіляції.
Замість цього ви можете оголосити масив як "лише для читання". Це має такий же ефект, як const, за винятком того, що значення може бути встановлено під час виконання. Він може бути встановлений лише один раз, і це значення, яке має значення лише заново (тобто const).
const int[] a = null;це не дуже корисний, а справді примірник константи масиву.
Оскільки на 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";
Titles[0], наприклад, фактично, спроба призначення тихо ігнорується. У поєднанні з неефективністю відтворення масиву кожного разу, мені цікаво, чи варто навіть такий підхід показати. Навпаки, другий підхід ефективний, і вам доведеться вийти зі свого шляху, щоб перемогти незмінність.
Якщо ви оголосили масив за інтерфейсом IReadOnlyList, ви отримаєте постійний масив з постійними значеннями, який оголошується під час виконання:
public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };
Доступно в .NET 4.5 і новіших версіях.
Рішення .NET Framework 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>розчином, де литий може бути використаний , щоб отримати доступ на запис до елементів , як показано на корисний відповідь mjepsen ігрова .
Те ж уразливість відноситься до до інтерфейсу , який, незважаючи на подібність у назві для класу , навіть не підтримує індексований доступ , що робить його принципово непридатним для надання доступу, подібного до масиву.)(string[])IReadOnlyCollection<T> ReadOnlyCollectionIReadOnlyCollectionне підтримує індексований доступ, тому його не можна використовувати тут. Крім того, як, наприклад, IReadOnlyList(який має індексований доступ), він піддається маніпуляції з елементами шляхом повернення до string[]. Іншими словами: ReadOnlyCollection(до якого ви не можете присвоїти рядковий рядок) - це найбільш надійне рішення. Не використовувати getter - це варіант (і я оновив відповідь, щоб відзначити це), але з загальнодоступними даними, можливо, краще дотримуватися властивості.
Для моїх потреб я визначаю staticмасив, а не неможливий, constі він працює:
public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
constз прикладу OP також працює, але це (або ваша відповідь) дозволяє змінити як: Titlesекземпляр, так і будь-яке значення. Тож який сенс у цій відповіді?
readonly
Ви можете скористатися іншим підходом: визначте постійний рядок для представлення масиву, а потім розділіть рядок на масив, коли він вам потрібен, наприклад
const string DefaultDistances = "5,10,15,20,25,30,40,50";
public static readonly string[] distances = DefaultDistances.Split(',');
Цей підхід дає вам константу, яка може зберігатися в конфігурації та перетворюватися в масив при необхідності.
Для повноти тепер у нас також є ImmutableArrays. Це має бути справді незмінним:
public readonly static ImmutableArray<string> Tiles = ImmutableArray.Create(new[] { "German", "Spanish", "Corrects", "Wrongs" });
Потрібна система System.Collections.Imumutable NuGet reference
https://msdn.microsoft.com/en-us/library/mt452182(v=vs.111).aspx
Це спосіб зробити те, що ви хочете:
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}
Це дуже схоже на виконання масиву для читання.
public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();; не потрібно відтворювати список при кожному отриманні, якщо ви все одно зробите його ReadOnlyCollection.
Це єдина правильна відповідь. Зараз ви не можете цього зробити.
Всі інші відповіді пропонують використовувати статичні змінні лише для читання, які схожі , але не такі, як константа. Константа важко закодована в збірку. Статична змінна лише для читання встановлюється один раз, ймовірно, як об'єкт ініціалізований.
Вони іноді взаємозамінні, але не завжди.
В якості альтернативи, щоб обійти проблему, що може бути змінена, з масивом, який читається, замість цього можна використовувати статичну властивість. (Окремі елементи все ще можуть бути змінені, але ці зміни будуть здійснені лише в локальній копії масиву.)
public static string[] Titles
{
get
{
return new string[] { "German", "Spanish", "Corrects", "Wrongs"};
}
}
Звичайно, це не буде особливо ефективно, оскільки щоразу створюється новий рядковий масив.
Найкраща альтернатива:
public static readonly byte[] ZeroHash = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };