Ярлык для создания одного списка элементов в C #


134

В C # есть встроенный ярлык для создания экземпляра List <T> только с одним элементом.

В настоящее время я делаю:

new List<string>( new string[] { "title" } ))

Наличие этого кода везде снижает читаемость. Я думал об использовании служебного метода, как это:

public static List<T> SingleItemList<T>( T value )
{
    return (new List<T>( new T[] { value } ));
}

Так что я мог сделать:

SingleItemList("title");

Есть более короткий / более чистый способ?

Спасибо.

Ответы:


245

Просто используйте это:

List<string> list = new List<string>() { "single value" };

Вы можете даже опустить фигурные скобки ():

List<string> list = new List<string> { "single value" };

Обновление: конечно, это также работает для более чем одной записи:

List<string> list = new List<string> { "value1", "value2", ... };

5
поместите 1 литерал в круглые скобки первого параметра, чтобы выделять память только для одного пробела, а не по умолчанию 10
— Джоэл Кехорн

5
По умолчанию получается 4, я считаю: новый список <string> {"Hello"} .Capacity == 4
— Джон Скит

39
var list = new List<string>(1) { "hello" };

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

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


Емкость установлена ​​на единицу. Я проголосовал за четыре ответа на этой странице, включая оба ответа Джона Скита, но считаю этот ответ наиболее правильным.
— Одинокий кодер

28

Идея Майкла об использовании методов расширения приводит к чему-то еще более простому:

public static List<T> InList<T>(this T item)
{
    return new List<T> { item };
}

Так что вы можете сделать это:

List<string> foo = "Hello".InList();

Я не уверен, нравится мне это или нет, заметьте ...


1
Я также не уверен, что мне это нравится: не странное ли это расширение типа строки (например)?
— M4N

1
Джон, я пока не описывал методы расширения в твоей книге :-) Это кажется странным, но мне нравится его полезность. Спасибо Мартин и Джон.
— Райан Иш

2
@Martin: это странное расширение каждого типа. Это обычно не рекомендуется, но это интересная общая идея.
— Джон Скит

4
Он использует некоторые внутренние домены, специфичные для языка, особенно с типами значений. Возьмем для примера: clock.AlertUser.In (1.Minute) читается намного лучше, чем clock.AlertUser (TimeSpan.FromMinutes (1));
— Майкл Медоуз

17

Другой ответ на мой предыдущий, основанный на знакомстве с Google Java Collections :

public static class Lists
{
    public static List<T> Of<T>(T item)
    {
        return new List<T> { item };
    }
}

Затем:

List<string> x = Lists.Of("Hello");

Я советую проверить GJC - в нем много интересного. (Лично я бы проигнорировал тег «alpha» - это всего лишь версия с открытым исходным кодом, которая называется «alpha»), и она основана на очень стабильном и интенсивно используемом внутреннем API. .)



7

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

public static List<T> WithItems(this List<T> list, params T[] items)
{
    list.AddRange(items);
    return list;
}

Это позволит вам сделать это:

List<string> strings = new List<string>().WithItems("Yes");

или

List<string> strings = new List<string>().WithItems("Yes", "No", "Maybe So");

Обновить

Теперь вы можете использовать инициализаторы списка:

var strings = new List<string> { "This", "That", "The Other" };

См. Http://msdn.microsoft.com/en-us/library/bb384062(v=vs.90).aspx


Может быть, это связано с более новыми версиями C # с 2009 года, но я считаю, new List<string> {"Yes"}что лучше ...?
— ErikE

@ErikE В соответствии с документацией Microsoft ( msdn.microsoft.com/en-us/library/bb384062(v=vs.90).aspx ) это было поддержано в Visual Studio 2008. Я не могу вспомнить, как далеко назад можно было сказать однозначно, если Я слишком усложнил это в то время. Обновление.
— Майкл Медоус

7

Еще один способ, найденный в «C # /. Net Little чудеса» (к сожалению, сайт больше не существует):

Enumerable.Repeat("value",1).ToList()

Смущает, но умно.
— PRMan

4

Для отдельного элемента, перечисляемого в java, это будет Collections.singleton ("string");

В C # это будет более эффективно, чем новый список:

public class SingleEnumerator<T> : IEnumerable<T>
{
    private readonly T m_Value;

    public SingleEnumerator(T value)
    {
        m_Value = value;
    }

    public IEnumerator<T> GetEnumerator()
    {
        yield return m_Value;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        yield return m_Value;
    }
}

но есть ли более простой способ использования фреймворка?


На самом деле это лучший ответ на мой взгляд. Это очень распространенный способ иметь один список элементов, чтобы уменьшить размер выделения. Если вы уже ищете ярлык, вы можете сочетать удобство с добром.
— Алекс


2

У меня есть эта маленькая функция:

public static class CoreUtil
{    
    public static IEnumerable<T> ToEnumerable<T>(params T[] items)
    {
        return items;
    }
}

Поскольку он не предписывает конкретный тип возвращаемого значения, он настолько универсален, что я использую его повсеместно. Ваш код будет выглядеть так

CoreUtil.ToEnumerable("title").ToList();

Но, конечно, это также позволяет

CoreUtil.ToEnumerable("title1", "title2", "title3").ToArray();

Я часто использую его, когда мне нужно добавить / добавить один элемент к выводу оператора LINQ. Например, чтобы добавить пустой элемент в список выбора:

CoreUtil.ToEnumerable("").Concat(context.TrialTypes.Select(t => t.Name))

Сохраняет несколько ToList()и Addзаявлений.

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



2

Вдохновленный другими ответами (и поэтому я могу подобрать его, когда мне это понадобится!), Но с именованием / стилем, выровненным по F # (который имеет стандартную singletonфункцию для структуры данных *):

namespace System.Collections.Generic
{
    public static class List
    {
        public static List<T> Singleton<T>(T value) => new List<T>(1) { value };
    }
}

* кроме ResizeArrayсебя конечно, отсюда и этот вопрос :)


На практике я на самом деле назвать его Createвыравнивать с другими помощниками я определяю , такие как Tuple.Create, Lazy.Create[2], и LazyTask.Createт.д.:

namespace System.Collections.Generic
{
    public static class List
    {
        public static List<T> Create<T>(T value) => new List<T>(1) { value };
    }
}

[2]

namespace System
{
    public static class Lazy
    {
        public static Lazy<T> Create<T>(Func<T> factory) => new Lazy<T>(factory);
    }
}

Спасибо! Мое решение также. Пара вещей: (1) ваша реализация списка не является общедоступной, поэтому ее нельзя использовать вне объявленной сборки, и (2) какова цель встраивания их в пространство имен System?
— Codure

@StephenRobinson причина для добавления Lazyрасширения в Systemтом, что оно Lazyнаходится в System[и, следовательно Create, появится в списках дополнений без a using]. Ничего нельзя получить, заставляя людей openискать разные имена? Делать другую вещь частной не было намеренным; исправлено
— Рубен Бартелинк

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.