Объявить массив const

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

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

Ответ 1

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

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

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

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

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

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

Ответ 2

Вы можете объявить массив как 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();

Ответ 3

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

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

Ответ 4

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

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

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

Аластер

Ответ 5

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

Ответ 6

Так как С# 6 вы можете записать его так:

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

См. также: С#: новый и улучшенный С# 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";

Ответ 7

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

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

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

Это очень похоже на выполнение массива readonly.

Ответ 8

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 объявить ее на уровне класса.

Вышеописанное:

  • Инициализирует свойство неявного поля поддержки после с помощью массива.

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

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

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

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

Ответ 9

Я считаю, что вы можете сделать это только для чтения.

Ответ 10

Массивы, вероятно, являются одной из тех вещей, которые могут быть оценены только при во время выполнения. Константы должны оцениваться во время компиляции. Попробуйте использовать "readonly" вместо "const".

Ответ 11

В качестве альтернативы, чтобы обойти проблему, связанную с элементами, которая может быть изменена с помощью массива readonly, вместо этого вы можете использовать статическое свойство. (Отдельные элементы все равно могут быть изменены, но эти изменения будут сделаны только на локальной копии массива.)

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

Конечно, это не будет особенно эффективно, так как каждый раз создается новый массив строк.

Ответ 12

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

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

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