Подтвердить что ты не робот

Встроенный экземпляр константного списка

Я пытаюсь сделать что-то вроде этого:

public const List<String> METRICS = new List<String>()
        {
            SourceFile.LOC,
            SourceFile.MCCABE,
            SourceFile.NOM,
            SourceFile.NOA,
            SourceFile.FANOUT,
            SourceFile.FANIN,
            SourceFile.NOPAR,
            SourceFile.NDC,
            SourceFile.CALLS
        };

Но, к сожалению, это не работает:

FileStorer.METRICS' is of type 'System.Collections.Generic.List<string>'. A const field of a reference type other than string can only be initialized with null.

Как я могу решить эту проблему?

4b9b3361

Ответ 1

const - для констант времени компиляции. Вы могли бы просто сделать это static readonly, но это применимо только к самой переменной METRICS (которая обычно должна быть метрикой, . Соглашения об именовании NET). Это не сделает список неизменным - так что кто-то может назвать METRICS.Add("shouldn't be here");

Вы можете использовать ReadOnlyCollection<T> для его обертки. Например:

public static readonly IList<String> Metrics = new ReadOnlyCollection<string>
    (new List<String> { 
         SourceFile.LoC, SourceFile.McCabe, SourceFile.NoM,
         SourceFile.NoA, SourceFile.FanOut, SourceFile.FanIn, 
         SourceFile.Par, SourceFile.Ndc, SourceFile.Calls });

ReadOnlyCollection<T> просто обертывает потенциально изменчивую коллекцию, но поскольку ничто иное не будет иметь доступ к List<T> впоследствии, вы можете считать общую коллекцию неизменной.

(Капитализация здесь в основном догадки - использование более полных имен сделает их более ясными, ИМО.)

Объявляете ли вы его как IList<string>, IEnumerable<string>, ReadOnlyCollection<string> или что-то еще до вас... если вы ожидаете, что его следует рассматривать только как последовательность, то IEnumerable<string>, вероятно, будет больше подходящее. Если порядок имеет значение, и вы хотите, чтобы люди могли получить к нему доступ по индексу, может оказаться уместным IList<T>. Если вы хотите сделать неизменность очевидной, объявление ее как ReadOnlyCollection<T> может быть удобным, но негибким.

Ответ 2

Вместо этого вам нужно будет использовать список static readonly. И если вы хотите, чтобы список был неизменным, вам может потребоваться использовать ReadOnlyCollection<T>, а не List<T>.

private static readonly ReadOnlyCollection<string> _metrics =
    new ReadOnlyCollection<string>(new[]
        {
            SourceFile.LOC,
            SourceFile.MCCABE,
            SourceFile.NOM,
            SourceFile.NOA,
            SourceFile.FANOUT,
            SourceFile.FANIN,
            SourceFile.NOPAR,
            SourceFile.NDC,
            SourceFile.CALLS
        });

public static ReadOnlyCollection<string> Metrics
{
    get { return _metrics; }
}

Ответ 3

.NET поддерживает действительно неизменяемые коллекции, представления только для чтения изменяемых коллекций и интерфейсы только для чтения, реализуемые изменяемой коллекцией.

Одной из таких неизменных коллекций является ImmutableArray <>, которую вы можете создать как a.ToImmutableArray() в вашем примере. Обязательно ознакомьтесь с другими вариантами списков MSDN, потому что вас может лучше обслуживать другая неизменная коллекция. Если вы хотите сделать копии оригинальной последовательности с небольшими изменениями, ImmutableList<> может быть, например, быстрее (хотя массив дешевле создавать и получать к нему доступ). Обратите внимание, что a.Add(...); допустимо, но возвращает новую коллекцию вместо изменения. Если у вас есть resharper, это предупредит вас, если вы проигнорируете возвращаемое значение чистого метода, такого как Add (и может быть расширение roslyn, чтобы сделать что-то подобное, о чем я не знаю). Если вы идете по этому пути - рассмотрите возможность полного пропуска List<> и перехода прямо к неизменным коллекциям.

Представления изменяемых коллекций, доступные только для чтения, немного менее безопасны, но поддерживаются в более старых версиях .NET. Тип упаковки называется ReadOnlyCollection <>, который в вашем примере вы можете создать как a.AsReadOnly(). Эта коллекция не гарантирует неизменность; это только гарантирует, что вы не можете изменить это. Некоторый другой фрагмент кода, который разделяет ссылку на базовый List<>, все еще может изменить его. Кроме того, ReadOnlyCollection также накладывает некоторые дополнительные издержки; поэтому вы можете не выиграть много, избегая неизменных коллекций по причинам производительности (TODO: сравните это утверждение). Вы можете использовать оболочку только для чтения, такую как эта, даже в общедоступном API-интерфейсе - нет способа (без отражения) получить базовый список. Однако, поскольку это часто не быстрее, чем неизменяемые коллекции, и это также не совсем безопасно, я рекомендую избегать ReadOnlyCollection <> - я больше никогда не использую это лично.

Интерфейсы только для чтения, реализуемые изменяемыми коллекциями, еще ниже по шкале безопасности, но быстро. Вы можете просто привести List<> как IReadOnlyList<>, что вы можете сделать в своем примере как IReadOnlyList lst = a. Это мои предпочтения во внутреннем коде - вы все еще получаете статическую безопасность типов, вы просто не защищены от вредоносного кода или кода, который использует проверки типов и неразумно выполняет приведение типов (но этого можно избежать с помощью проверок кода в моем опыте). Меня никогда не укусил этот выбор, но он менее безопасен, чем два вышеуказанных варианта. С другой стороны, он не несет никаких расходов и работает быстрее. Если вы обычно делаете это, вы можете захотеть определить метод расширения, который будет выполнять преобразование для вас (приведение может быть небезопасным в С#, потому что они не только выполняют безопасное преобразование, но, возможно, отказывают в понижении, и преобразованиях, определенных пользователем - так что это хороший Идея избегать явных приведений, где только можно).

Обратите внимание, что во всех случаях только сама последовательность доступна только для чтения. Базовые объекты не затрагиваются (например, int или string являются неизменяемыми, но более сложные объекты могут или не могут быть).

Ответ 4

Вы ищете простой код, например:

    List<string> tagList = new List<string>(new[]
    {
         "A"
        ,"B"
        ,"C"
        ,"D"
        ,"E"
    });