Відповіді:
Так, але вам потрібно оголосити це 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>
ReadOnlyCollection
IReadOnlyCollection
не підтримує індексований доступ, тому його не можна використовувати тут. Крім того, як, наприклад, 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 };