Объявить константный массив - PullRequest
403 голосов
/ 28 февраля 2011

Можно ли написать что-то похожее на следующее?

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

Ответы [ 13 ]

613 голосов
/ 28 февраля 2011

Да, но вам нужно объявить это readonly вместо const:

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

Причина в том, что const может применяться только к полю, значение которого известно во время компиляции. Показанный вами инициализатор массива не является константным выражением в C #, поэтому он выдает ошибку компилятора.

Объявление его readonly решает эту проблему, поскольку значение не инициализируется до времени выполнения (хотя гарантированно инициализируется до первого использования массива).

В зависимости от того, чего вы в конечном итоге хотите достичь, вы можете также рассмотреть возможность объявления перечисления:

public enum Titles { German, Spanish, Corrects, Wrongs };
52 голосов
/ 28 февраля 2011

Вы можете объявить массив как 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();
42 голосов
/ 28 февраля 2011

Вы не можете создать массив 'const', поскольку массивы являются объектами и могут быть созданы только во время выполнения, а объекты const разрешаются во время компиляции.

Вместо этого вы можете объявить свой массив как"ReadOnly".Это имеет тот же эффект, что и const, за исключением того, что значение может быть установлено во время выполнения.Он может быть установлен только один раз, и после этого он будет иметь значение только для чтения (т. Е. Постоянное).

11 голосов
/ 09 августа 2016

Начиная с 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";
6 голосов
/ 17 октября 2017

Если вы объявите массив за интерфейсом IReadOnlyList, вы получите постоянный массив с постоянными значениями, который объявлен во время выполнения:

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

Доступно в .NET 4.5 и выше.

6 голосов
/ 26 сентября 2013

Вы можете выбрать другой подход: определить постоянную строку для представления вашего массива, а затем разбить строку на массив, когда вам это нужно, например,

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

Этот подход дает вам постоянную,сохраняется в конфигурации и при необходимости преобразуется в массив.

Alastair

5 голосов
/ 05 апреля 2017

A .NET Framework v4.5 + решение , улучшающее ответ tdbeckett :

using System.Collections.ObjectModel;

// ...

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

Примечание: Учитывая, что коллекция концептуально постоянна, может иметь смысл static объявить ее на уровне class .

Выше:

  • Инициализирует неявное базовое поле свойства один раз с массивом.

    • Обратите внимание, что { get; } - то есть объявление только свойства getter - это то, что делает само свойство неявно доступным только для чтения (попытка объединить readonly с { get; } на самом деле синтаксическая ошибка).

    • В качестве альтернативы, вы можете просто пропустить { get; } и добавить readonly, чтобы создать поле вместо свойства, как в вопросе, но выставить public Элементы данных как свойства, а не поля - хорошая привычка для формирования.

  • Создает массив- подобный структуру (разрешающий индексированный доступ ), который действительно и надежно доступен только для чтения ( концептуально постоянная, однажды созданная), как по отношению к:

    • предотвращение изменения коллекции в целом (например, путем удаления или добавления элементов или назначения новой коллекции переменной).
    • предотвращение модификации отдельных элементов .
      (Даже косвенное изменение невозможно - в отличие от решения IReadOnlyList<T>, где a (string[]) приведение может использоваться для получения доступа на запись к элементам , как показано в полезном ответе mjepsen .
      Та же самая уязвимость применяется к IReadOnlyCollection<T> интерфейсу , который, несмотря на сходство в названии с class ReadOnlyCollection, даже не поддерживает indexed access , что делает его принципиально непригодным для предоставления доступа к массиву.)
5 голосов
/ 24 апреля 2013

Для моих нужд я определяю static массив, а не невозможный const, и он работает: public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

3 голосов
/ 09 августа 2014

Это способ сделать то, что вы хотите:

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

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

Это очень похоже на создание массива только для чтения.

2 голосов
/ 26 июля 2018

Для полноты картины в нашем распоряжении также имеются массивы ImmutableArrays. Это должно быть действительно неизменным:

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

Требуется ссылка System.Collections.Imutable NuGet

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

...