Каков правильный способ инициализации непустой статической коллекции в С# 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), но миграция не является вариантом для нашей системы на данный момент.
Чтобы прояснить мой первоначальный вопрос - я ищу способ кратко заявить простую статическую коллекцию, такую как простой постоянный набор строк. Стиль статического инициализатора также очень полезен для коллекций более сложных объектов.
Спасибо!
Ответы
Ответ 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 лучше, так как в случае статических конструкторов среда выполнения должна проверять, был ли вызван статический конструктор перед каждым доступом к классу.