Ярлик для створення списку окремих елементів у C #


134

У C # є вбудований ярлик для створення списку <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 за замовчуванням
Joel Coehoorn

5
За замовчуванням дорівнює 4, я вважаю: новий Список <string> {"Привіт"}. Можливість == 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 :

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

Тоді:

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

Я раджу перевірити GJC - у ньому є багато цікавого. (Особисто я б ігнорував тег "альфа" - це лише версія з відкритим кодом, яка "альфа", і вона заснована на дуже стабільному та широко використовуваному внутрішньому 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 Відповідно до документації Майкрософт ( msdn.microsoft.com/en-us/library/bb384062(v=vs.90).aspx ) це було підтримано в Visual Studio 2008. Я не можу згадати це далеко назад, щоб остаточно сказати, якщо Я на той час це надто ускладнив. Оновлення.
Майкл Медоуз

7

Ще один спосіб, знайдений на "C # /. Чисті маленькі чудеса" (на жаль, сайт більше не існує):

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

Заплутаний, але розумний.
PRMan

4

Для одного елемента, перерахованого в Java, це буде Collections.singleton ("рядок");

У 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) яка мета їх введення в простір імен системи?
Codure

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.