Как правильно инициализировать непустую статическую коллекцию в C # 2.0? - PullRequest
19 голосов
/ 05 января 2009

Я хочу инициализировать статическую коллекцию в моем классе C # - что-то вроде этого:

public class Foo {
  private static readonly ICollection<string> g_collection = ???
}

Я не уверен в правильном способе сделать это; в Java я мог бы сделать что-то вроде:

private static final Collection<String> g_collection = Arrays.asList("A", "B");

есть ли подобная конструкция в C # 2.0?

Я знаю, что в более поздних версиях C # / .NET вы можете выполнять инициализаторы коллекций (http://msdn.microsoft.com/en-us/library/bb384062.aspx),, но в настоящее время миграция не подходит для нашей системы.

Чтобы уточнить мой исходный вопрос - я ищу способ кратко объявить простую статическую коллекцию, такую ​​как простая константа коллекции строк. Способ в стиле static-initializer также очень полезен для коллекций более сложных объектов.

Спасибо!

Ответы [ 9 ]

27 голосов
/ 05 января 2009

Если я полностью понимаю ваш вопрос, кажется, что некоторые другие упустили момент, вы хотите создать статическую коллекцию, аналогичную Java, в которой вы можете объявлять и заполнять одну строку кода без необходимости создайте специальный метод для этого (согласно некоторым другим предложениям). Это можно сделать с помощью литерала массива (для предотвращения прокрутки написанного в две строки):

private static readonly ICollection<string> Strings = 
  new string[] { "Hello", "World" };

Это одновременно объявляет и заполняет новую коллекцию только для чтения списком элементов. Работает в 2.0 и 3.5, я проверил это просто чтобы быть вдвойне уверенным.

В 3.5, хотя вы можете использовать вывод типа, так что вам больше не нужно использовать массив string [], который удаляет еще больше нажатий клавиш:

private static readonly ICollection<string> Strings = 
  new[] { "Hello", "World" };

Обратите внимание на отсутствующий тип "string" во второй строке строки. Строка автоматически выводится из содержимого инициализатора массива.

Если вы хотите заполнить его списком, просто измените новую строку [] для нового списка а-ля:

private static readonly ICollection<string> Strings = 
  new List<string>() { "Hello", "World" };

Конечно, поскольку ваш тип IEnumerable, а не конкретная реализация, если вы хотите получить доступ к методам, специфичным для List , таким как .ForEach (), вам потребуется преобразовать его в List:

((List<string>)Strings).ForEach(Console.WriteLine);

Но это небольшая цена за переносимость [это слово?].

9 голосов
/ 05 января 2009

Статическая конструкция:

public class Foo
{
    private static readonly ICollection<string> _collection;

    static Foo()
    {
        _collection = new List<string>();
        _collection.Add("One");
        _collection.Add("Two");
    }
}

Но учтите, что в этом случае вы можете просто инициализировать коллекцию inline (рекомендуется для соображений производительности ):

private static readonly ICollection<string> _collection = new List<string>(new string[] { "One", "Two" });

Это действительно зависит от того, насколько сложен ваш код инициализации.

5 голосов
/ 05 января 2009

Возможно, вы можете вызвать статический метод:

public class Foo
{
    private static readonly ICollection<string> g_collection = initializeCollection();

    private static ICollection<string> initializeCollection()
    {
        ... TODO allocate and return something here ...
    }
}

Или наличие статического конструктора (как предлагали другие) может быть эквивалентным или даже более идиоматическим.

1 голос
/ 05 января 2009

кроме статического конструктора, это также будет работать

    public class Foo
    {
        private static readonly ICollection<string> _collection = 
              new List<string>(new string[] { "elem1", "elem2", "...", "elemn" });
    }
0 голосов
/ 05 января 2009

У вас есть два варианта:

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

  2. Используйте статический конструктор для создания коллекции, заполните ее и инициализируйте для статической переменной.

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

0 голосов
/ 05 января 2009

Используйте статический конструктор следующим образом:

public class Foo
{
    static readonly ICollection<string> g_collection;

    // Static constructor
    static Foo()
    {
        g_collection = new List<string>();
        g_collection.Add("Hello");
        g_collection.Add("World!");
    }
}
0 голосов
/ 05 января 2009

Мне нравится использовать IEnumerable<T>.ToList().
Кроме того, если ваша коллекция должна быть доступна только для чтения, вы можете использовать System.Collections.ObjectModel.ReadOnlyCollection.

private readonly ICollection<string> collection = new string[] { "a", "b", "c" }.ToList();

private readonly ReadOnlyCollection<string> collection2 = new ReadOnlyCollection<string>(new string[] { "a", "b", "c" });

EDIT:
Опять же, если вы используете его как ICollection, вы можете просто использовать конструктор массива (поскольку T[] - это IList<T> и ICollection<T>). Имейте в виду, что в этом случае многие изменяющие методы, такие как Add, потерпят неудачу:

private readonly ICollection<string> = new string[] { "a", "b", "c" };

РЕДАКТИРОВАТЬ # 2: Я только что понял, что ToList является функцией расширения и может использоваться только в C # 3.0. Вы все еще можете использовать конструктор List, хотя:

private readonly IList<string> = new List<string>(new string[] { "a", "b", "c" });

Тем не менее, я предпочитаю ReadOnlyCollection для списков только для чтения.

0 голосов
/ 05 января 2009

вы можете объявить собственный класс коллекции и добавить в него свой собственный ctor ...

  public class MyFooCollection: Collection<string>
   {
      public MyFooCollection(string[] values)
      {
          foreach (string s in values)  base.Add(s); 
      }
   }

тогда в коде вашего клиента вы можете написать

  private static final MyFooCollection g_collection = 
         new MyFooCollection(new string[] {"A", "B"});
0 голосов
/ 05 января 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...