Skrót do tworzenia listy pojedynczych pozycji w C #


134

W C # czy istnieje skrót wbudowany do tworzenia wystąpienia List <T> z tylko jednym elementem.

Obecnie robię:

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

Posiadanie tego kodu wszędzie zmniejsza czytelność. Myślałem o użyciu takiej metody narzędziowej:

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

Więc mogłem zrobić:

SingleItemList("title");

Czy istnieje krótszy / czystszy sposób?

Dzięki.

Odpowiedzi:


245

Po prostu użyj tego:

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

Możesz nawet pominąć () nawiasy klamrowe:

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

Aktualizacja: oczywiście działa to również w przypadku więcej niż jednego wpisu:

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

5
umieść literał 1 w nawiasach pierwszej opcji, aby miejsce na dokładnie jedno miejsce zostało przydzielone zamiast domyślnego 10
Joel Coehoorn

5
Domyślnie kończy się na 4, jak sądzę: nowa Lista <string> {"Hello"} .Capacity == 4
Jon Skeet

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

Bardzo podobny do tego, co opublikowali inni, z tą różnicą, że zapewnia początkowe przydzielenie miejsca tylko na jeden element.

Oczywiście, jeśli wiesz, że później dodasz kilka rzeczy, może to nie być dobry pomysł, ale warto o tym raz wspomnieć.


Pojemność ustawiona na jeden. Głosowałem na cztery odpowiedzi na tej stronie, w tym obie odpowiedzi Jona Skeeta, ale uważam, że ta jest najbardziej poprawna.
The Lonely Coder,

28

Pomysł Michaela na używanie metod rozszerzających prowadzi do czegoś jeszcze prostszego:

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

Więc możesz to zrobić:

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

Nie jestem pewien, czy mi się to podoba, czy nie, uwaga ...


1
Nie jestem też pewien, czy mi się podoba: czy to nie jest „dziwne” rozszerzenie typu string (na przykład)?
M4N

1
Nie dotarłem jeszcze do metod rozszerzających w twojej książce, Jon :-) To wydaje się trochę dziwne, ale podoba mi się jego użyteczność. Dzięki Martin i Jon.
Ryan Ische

2
@Martin: To dziwne rozszerzenie każdego typu. Jest to generalnie odradzane, ale jest to interesujący ogólny pomysł.
Jon Skeet

4
Wymaga niektórych zastosowań języka specyficznych dla domeny wewnętrznej, szczególnie w przypadku typów wartości. Weźmy na przykład: clock.AlertUser.In (1.Minute) czyta znacznie lepiej niż clock.AlertUser (TimeSpan.FromMinutes (1));
Michael Meadows,

17

Inna odpowiedź do mojej wcześniejszej, oparta na ekspozycji w Google Java Collections :

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

Następnie:

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

Radzę sprawdzić GJC - zawiera wiele interesujących rzeczy. (Osobiście zignorowałbym tag "alfa" - to tylko wersja open source jest "alfa" i jest oparta na bardzo stabilnym i mocno używanym wewnętrznym API .)



7

Użyj metody rozszerzenia z łączeniem metod.

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

To pozwoliłoby ci to zrobić:

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

lub

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

Aktualizacja

Możesz teraz używać inicjatorów list:

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

Zobacz http://msdn.microsoft.com/en-us/library/bb384062(v=vs.90).aspx


Może jest to spowodowane nowszymi wersjami C # od 2009 roku, ale uważam, że new List<string> {"Yes"}jest lepszy ...?
ErikE

@ErikE Zgodnie z dokumentacją Microsoft ( msdn.microsoft.com/en-us/library/bb384062(v=vs.90).aspx ) było to obsługiwane w programie Visual Studio 2008. Nie pamiętam aż tak dawno, aby powiedzieć ostatecznie, czy Wtedy to zbytnio skomplikowałem. Aktualizacja.
Michael Meadows,

7

Jeszcze inny sposób, znaleziony w "C # /. Net Little Wonders" (niestety, strona już nie istnieje):

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

Zagmatwane, ale sprytne.
PRMan

4

Dla pojedynczego elementu wyliczalnego w java byłoby to Collections.singleton ("string");

W języku c # będzie to bardziej wydajne niż nowa lista:

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

ale czy istnieje prostszy sposób korzystania z frameworka?


Moim zdaniem to najlepsza odpowiedź. Bardzo częstym wzorcem jest posiadanie jednej listy pozycji w celu zmniejszenia rozmiaru alokacji. Jeśli już szukasz skrótu, równie dobrze możesz połączyć wygodę z dobrem.
Alex


2

Mam tę małą funkcję:

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

Ponieważ nie przepisuje konkretnego typu powrotu, jest to tak ogólne, że używam go wszędzie. Twój kod będzie wyglądał

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

Ale oczywiście pozwala też

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

Często używam go, gdy muszę dołączyć / poprzedzić jeden element na wyjściu instrukcji LINQ. Na przykład, aby dodać pusty element do listy wyboru:

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

Zapisuje kilka ToList()i Addwypowiedzi.

(Późna odpowiedź, ale natknąłem się na tego staruszka i pomyślałem, że może to być pomocne)



2

Zainspirowany innymi odpowiedziami (więc mogę je odebrać, kiedy tylko tego potrzebuję!), Ale z nazewnictwem / stylem wyrównanym z F # (który ma standardową singletonfunkcję na strukturę danych *):

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

* ResizeArrayoczywiście poza sobą, stąd to pytanie :)


W praktyce I rzeczywiście nazwać Create, aby wyrównać z innych pomocników zdefiniować takie jak Tuple.Create, Lazy.Create[2], LazyTask.Createitp:

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

Dzięki! Moje rozwiązanie też. Kilka rzeczy: (1) Twoja implementacja listy nie jest publiczna, więc nie może być używana poza deklarowanym zestawem, i (2) jaki jest cel upychania ich w przestrzeni nazw System?
Codure

@StephenRobinson powodem umieszczenia Lazyrozszerzenia Systemjest to, że Lazysamo jest w System[i dlatego Createpojawiałoby się na listach kompilacji bez znaku using]. Nie ma nic do zyskania na zmuszaniu ludzi do korzystania openz przestrzeni nazw diff? Uczynienie innej rzeczy prywatnością nie było zamierzone; naprawiono
Ruben Bartelink

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.