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

Каков правильный способ инициализации непустой статической коллекции в С# 2.0?

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

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

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

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

Есть ли аналогичная конструкция в С# 2.0?

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

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

Спасибо!

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

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

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

Но это небольшая цена за миграцию (это слово?).

Ответ 2

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

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" });

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

Ответ 3

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

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

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

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

Ответ 4

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

    public class Foo
    {
        private static readonly ICollection<string> _collection = 
              new List<string>(new string[] { "elem1", "elem2", "...", "elemn" });
    }

Ответ 5

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

Ответ 6

вы можете объявить пользовательский класс коллекции и добавить свой собственный 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"});

Ответ 7

Мне нравится использовать 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 является функцией расширения и может использоваться только в С# 3.0. Вы все равно можете использовать конструктор List:

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

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

Ответ 8

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

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!");
    }
}

Ответ 9

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

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

  • Используйте статический конструктор, чтобы создать коллекцию, заполнить ее и инициализировать ее статической переменной.

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