Przekazywanie pojedynczego elementu jako IEnumerable <T>


377

Czy istnieje wspólny sposób przekazywania pojedynczego elementu typu Tdo metody, która oczekuje IEnumerable<T>parametru? Językiem jest C #, wersja ramowa 2.0.

Obecnie używam metody pomocniczej (to .Net 2.0, więc mam całą masę rzutowych / rzutujących metod pomocniczych podobnych do LINQ), ale to po prostu wydaje się głupie:

public static class IEnumerableExt
{
    // usage: IEnumerableExt.FromSingleItem(someObject);
    public static IEnumerable<T> FromSingleItem<T>(T item)
    {
        yield return item; 
    }
}

Innym sposobem byłoby oczywiście utworzenie i wypełnienie pola a List<T>lub an Arrayi podanie go zamiast IEnumerable<T>.

[Edytuj] Jako metodę rozszerzenia może mieć nazwę:

public static class IEnumerableExt
{
    // usage: someObject.SingleItemAsEnumerable();
    public static IEnumerable<T> SingleItemAsEnumerable<T>(this T item)
    {
        yield return item; 
    }
}

Czy coś mi umyka?

[Edytuj2] Odkryliśmy someObject.Yield()(jak sugeruje @Peter w komentarzach poniżej), że jest to najlepsza nazwa dla tej metody rozszerzenia, głównie ze względu na zwięzłość, więc tutaj jest wraz z komentarzem XML, jeśli ktoś chce go złapać:

public static class IEnumerableExt
{
    /// <summary>
    /// Wraps this object instance into an IEnumerable&lt;T&gt;
    /// consisting of a single item.
    /// </summary>
    /// <typeparam name="T"> Type of the object. </typeparam>
    /// <param name="item"> The instance that will be wrapped. </param>
    /// <returns> An IEnumerable&lt;T&gt; consisting of a single item. </returns>
    public static IEnumerable<T> Yield<T>(this T item)
    {
        yield return item;
    }
}

6
Zrobiłbym niewielką modyfikację w treści metody rozszerzenia: if (item == null) yield break; teraz przestajesz przekazywać wartości zerowe, a także korzystać z (trywialnego) wzorca obiektów zerowych IEnumerable. ( foreach (var x in xs)radzi sobie z pustą, xsdobrze). Nawiasem mówiąc, ta funkcja jest jednostką monadyczną dla listy monad IEnumerable<T>, a biorąc pod uwagę festiwal miłosny monad w Microsoft, jestem zaskoczony, że coś takiego nie znajduje się w ramach.
Matt Enright

2
W przypadku metody rozszerzenia nie powinieneś nazywać jej, AsEnumerableponieważ wbudowane rozszerzenie o tej nazwie już istnieje . (Gdy Timplementuje IEnumerablenp string..)
Jon-Eric,

22
A może nazwać metodę Yield? Nic nie przebije zwięzłości.
Philip Guin,

4
Sugestie dotyczące nazewnictwa tutaj. „SingleItemAsEnumerable” jest trochę gadatliwy. „Wydajność” opisuje implementację, a nie interfejs - co nie jest dobre. Aby uzyskać lepszą nazwę, sugeruję „AsSingleton”, które odpowiadają dokładnemu znaczeniu zachowania.
Earth Engine

4
Nienawidzę left==nullczeku tutaj. Łamie piękno kodu i przestaje być bardziej elastyczny - co jeśli kiedyś okaże się, że trzeba wygenerować singleton z czymś, co może być zerowe? Mam na myśli, że new T[] { null }to nie to samo, co new T[] {}pewnego dnia może być konieczne ich rozróżnienie.
Earth Engine

Odpowiedzi:


100

Twoja metoda pomocnicza to najczystszy sposób, aby to zrobić, IMO. Jeśli przekażesz listę lub tablicę, nieuczciwy fragment kodu może rzucić go i zmienić zawartość, co w niektórych sytuacjach może prowadzić do dziwnego zachowania. Możesz użyć kolekcji tylko do odczytu, ale może to wymagać jeszcze większego zawijania. Myślę, że twoje rozwiązanie jest tak schludne, jak to tylko możliwe.


cóż, jeśli lista / tablica jest budowana ad-hoc, jej zakres kończy się po wywołaniu metody, więc nie powinno to powodować problemów
Mario F

Jeśli zostanie wysłany jako tablica, jak można go zmienić? Wydaje mi się, że można by rzucić na tablicę, a następnie zmienić odniesienie do czegoś innego, ale co by to zrobiło? (Prawdopodobnie coś mi brakuje ...)
Svish

2
Załóżmy, że zdecydowałeś się utworzyć jeden wyliczacz, aby przejść do dwóch różnych metod ... a następnie pierwszy rzucił go na tablicę i zmienił zawartość. Następnie przekazujesz go jako argument innej metodzie, nieświadomej zmiany. Nie twierdzę, że to prawdopodobne, po prostu posiadanie czegoś zmiennego, kiedy nie musi być, jest mniej schludne niż niezmienność natury.
Jon Skeet

3
To jest odpowiedź zaakceptowana i najprawdopodobniej zostanie przeczytana, dlatego dodam tutaj moje obawy. Próbowałem tej metody, ale złamałem wcześniej kompilacją wywołanie myDict.Keys.AsEnumerable()gdzie myDictbył typu Dictionary<CheckBox, Tuple<int, int>>. Po zmianie nazwy metody rozszerzenia na SingleItemAsEnumerablewszystko zaczęło działać. Nie można przekonwertować IEnumerable <Dictionary <CheckBox, System.Tuple <int, int >>. KeyCollection> ”na„ IEnumerable <CheckBox> ”. Istnieje wyraźna konwersja (brakuje Ci obsady?) Mogę przez chwilę żyć z hackiem, ale czy inni hakerzy mogą znaleźć lepszy sposób?
Hamish Grubijan 17.10.11

3
@HamishGrubijan: Wygląda na to, że chciałeś dictionary.Valueszacząć. Zasadniczo nie jest jasne, co się dzieje, ale sugeruję, aby rozpocząć nowe pytanie na ten temat.
Jon Skeet

133

Cóż, jeśli metoda oczekuje IEnumerable, że musisz przekazać coś, co jest listą, nawet jeśli zawiera tylko jeden element.

przechodzący

new[] { item }

jak sądzę, argument powinien wystarczyć


32
Myślę, że możesz nawet upuścić T, ponieważ zostanie on wywnioskowany (chyba, że ​​się tu bardzo mylę: p)
Svish

2
Myślę, że nie jest to wywnioskowane w C # 2.0.
Groo

4
„Language is C #, framework framework 2” Kompilator C # 3 może wywnioskować T, a kod będzie w pełni kompatybilny z .NET 2.
sisve

najlepsza odpowiedź jest na dole ?!
Falco Alexander,

2
@Svish Zasugerowałem i zredagowałem odpowiedź, aby zrobić tylko to - jesteśmy teraz w 2020 roku, więc powinien to być „standardowy”
imho

120

W C # 3.0 możesz użyć klasy System.Linq.Enumerable:

// using System.Linq

Enumerable.Repeat(item, 1);

Spowoduje to utworzenie nowego IEnumerable, który zawiera tylko twój element.


26
Myślę, że to rozwiązanie sprawi, że kod będzie trudniejszy do odczytania. :( Powtarzanie na jednym elemencie jest dość sprzeczne z intuicją, nie sądzisz?
Drahakar

6
Powtórz raz, gdy będzie dla mnie ok. Znacznie prostsze rozwiązanie bez konieczności martwienia się o dodanie kolejnej metody rozszerzenia i zapewnienie, że przestrzeń nazw zostanie uwzględniona wszędzie tam, gdzie chcesz jej użyć.
si618

13
Tak, właściwie po prostu korzystam z new[]{ item }siebie, pomyślałem, że to ciekawe rozwiązanie.
luksan

7
To rozwiązanie to pieniądze.
ProVega,

IMHO powinna to być zaakceptowana odpowiedź. Jest łatwy do odczytania, zwięzły i zaimplementowany w jednym wierszu na BCL, bez niestandardowej metody rozszerzenia.
Ryan

35

W C # 3 (wiem, że powiedziałeś 2) możesz napisać ogólną metodę rozszerzenia, która może sprawić, że składnia będzie nieco bardziej akceptowalna:

static class IEnumerableExtensions
{
    public static IEnumerable<T> ToEnumerable<T>(this T item)
    {
        yield return item;
    }
}

kod klienta jest wtedy item.ToEnumerable().


Dzięki, jestem tego świadomy (działa w .Net 2.0, jeśli używam C # 3.0), po prostu zastanawiałem się, czy istnieje wbudowany mechanizm do tego.
Groo,

12
To naprawdę fajna alternatywa. Chcę tylko zasugerować zmianę nazwy, aby ToEnumerableuniknąć bałaganuSystem.Linq.Enumerable.AsEnumerable
Fede,

3
Na marginesie, istnieje już ToEnumerablemetoda rozszerzenia dla IObservable<T>, więc ta nazwa metody również zakłóca istniejące konwencje. Szczerze mówiąc, sugerowałbym, aby w ogóle nie stosować metody rozszerzenia, ponieważ jest ona zbyt ogólna.
cwharris,

14

Ta metoda pomocnicza działa dla przedmiotu lub wielu.

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

1
Przydatna odmiana, ponieważ obsługuje więcej niż jeden element. Podoba mi się, że polega na paramsbudowaniu tablicy, więc wynikowy kod wygląda czysto. Nie zdecydowałem, czy podoba mi się to bardziej, czy mniej niż w new T[]{ item1, item2, item3 };przypadku wielu przedmiotów.
ToolmakerSteve

Mądry ! Uwielbiam
Mitsuru Furuta

10

Jestem trochę zaskoczony, że nikt nie zasugerował nowego przeciążenia metody argumentem typu T, aby uprościć interfejs API klienta.

public void DoSomething<T>(IEnumerable<T> list)
{
    // Do Something
}

public void DoSomething<T>(T item)
{
    DoSomething(new T[] { item });
}

Teraz twój kod klienta może po prostu to zrobić:

MyItem item = new MyItem();
Obj.DoSomething(item);

lub z listą:

List<MyItem> itemList = new List<MyItem>();
Obj.DoSomething(itemList);

19
Co więcej, możesz mieć, DoSomething<T>(params T[] items)co oznacza, że ​​kompilator poradzi sobie z konwersją jednego elementu na tablicę. (Pozwoliłoby to również na przekazanie wielu osobnych elementów i ponownie kompilator poradziłby sobie z ich konwersją do tablicy.)
LukeH

7

Albo (jak już powiedziano)

MyMethodThatExpectsAnIEnumerable(new[] { myObject });

lub

MyMethodThatExpectsAnIEnumerable(Enumerable.Repeat(myObject, 1));

Na marginesie, ostatnia wersja może być również przyjemna, jeśli chcesz mieć pustą listę anonimowych obiektów, np

var x = MyMethodThatExpectsAnIEnumerable(Enumerable.Repeat(new { a = 0, b = "x" }, 0));

Dzięki, chociaż Enumerable.Repeat jest nowy w .Net 3.5. Wygląda na to, że zachowuje się podobnie do powyższej metody pomocniczej.
Groo

7

Jak właśnie znalazłem i zobaczyłem, że użytkownik LukeH również sugerował, ładny prosty sposób na zrobienie tego jest następujący:

public static void PerformAction(params YourType[] items)
{
    // Forward call to IEnumerable overload
    PerformAction(items.AsEnumerable());
}

public static void PerformAction(IEnumerable<YourType> items)
{
    foreach (YourType item in items)
    {
        // Do stuff
    }
}

Ten wzór pozwoli ci wywołać tę samą funkcjonalność na wiele sposobów: pojedynczy element; wiele elementów (oddzielonych przecinkami); tablica; lista; wyliczenie itp.

Nie jestem jednak w 100% pewien skuteczności użycia metody AsEnumerable, ale to działa.

Aktualizacja: funkcja AsEnumerable wygląda całkiem wydajnie! ( odniesienie )


Właściwie wcale nie potrzebujesz .AsEnumerable(). Tablica YourType[]już implementuje IEnumerable<YourType>. Ale moje pytanie dotyczyło przypadku, gdy dostępna jest tylko druga metoda (w twoim przykładzie), a używasz .NET 2.0 i chcesz przekazać pojedynczy element.
Groo,

2
Tak, ale zauważysz, że możesz dostać przepełnienie stosu ;-)
teppicymon

I żeby odpowiedzieć na twoje prawdziwe pytanie (nie na to, na które tak naprawdę chciałem sam odpowiedzieć!), Tak, musisz przekonwertować je na tablicę zgodnie z odpowiedzią Mario
teppicymon

2
A może po prostu zdefiniować IEnumerable<T> MakeEnumerable<T>(params T[] items) {return items;}metodę? Można to następnie wykorzystać ze wszystkim, czego można się spodziewać IEnumerable<T>, dla dowolnej liczby dyskretnych elementów. Kod powinien być zasadniczo tak samo wydajny, jak definiowanie specjalnej klasy do zwracania pojedynczego elementu.
supercat

6

Chociaż jest to przesada w przypadku jednej metody, uważam, że niektórzy ludzie mogą uznać Interaktywne rozszerzenia za przydatne.

Interaktywne rozszerzenia (Ix) firmy Microsoft obejmują następującą metodę.

public static IEnumerable<TResult> Return<TResult>(TResult value)
{
    yield return value;
}

Które można wykorzystać w następujący sposób:

var result = EnumerableEx.Return(0);

Ix dodaje nową funkcjonalność, której nie znaleziono w oryginalnych metodach rozszerzenia Linq, i jest bezpośrednim wynikiem utworzenia Reactive Extensions (Rx).

Pomyśl, Linq Extension Methods+ Ix= Rxdla IEnumerable.

Możesz znaleźć zarówno Rx, jak i Ix na CodePlex .


5

Jest to 30% szybsze niż yieldlub w Enumerable.Repeatprzypadku użycia z foreachpowodu optymalizacji kompilatora C # i tej samej wydajności w innych przypadkach.

public struct SingleSequence<T> : IEnumerable<T> {
    public struct SingleEnumerator : IEnumerator<T> {
        private readonly SingleSequence<T> _parent;
        private bool _couldMove;
        public SingleEnumerator(ref SingleSequence<T> parent) {
            _parent = parent;
            _couldMove = true;
        }
        public T Current => _parent._value;
        object IEnumerator.Current => Current;
        public void Dispose() { }

        public bool MoveNext() {
            if (!_couldMove) return false;
            _couldMove = false;
            return true;
        }
        public void Reset() {
            _couldMove = true;
        }
    }
    private readonly T _value;
    public SingleSequence(T value) {
        _value = value;
    }
    public IEnumerator<T> GetEnumerator() {
        return new SingleEnumerator(ref this);
    }
    IEnumerator IEnumerable.GetEnumerator() {
        return new SingleEnumerator(ref this);
    }
}

w tym teście:

    // Fastest among seqs, but still 30x times slower than direct sum
    // 49 mops vs 37 mops for yield, or c.30% faster
    [Test]
    public void SingleSequenceStructForEach() {
        var sw = new Stopwatch();
        sw.Start();
        long sum = 0;
        for (var i = 0; i < 100000000; i++) {
            foreach (var single in new SingleSequence<int>(i)) {
                sum += single;
            }
        }
        sw.Stop();
        Console.WriteLine($"Elapsed {sw.ElapsedMilliseconds}");
        Console.WriteLine($"Mops {100000.0 / sw.ElapsedMilliseconds * 1.0}");
    }

Dzięki, sensowne jest stworzenie struktury dla tego przypadku, aby zmniejszyć obciążenie GC w ciasnych pętlach.
Groo,

1
Zarówno moduł wyliczający, jak i moduł wyliczeniowy zostaną zwrócone w pudełku, gdy zostaną zwrócone ....
Stephen Drew

2
Nie porównuj za pomocą stopera. Użyj Benchmark.NET github.com/dotnet/BenchmarkDotNet
NN_

1
Właśnie to zmierzyłem, a new [] { i }opcja jest około 3,2 razy szybsza niż Twoja opcja. Również twoja opcja jest około 1,2 razy szybsza niż rozszerzenie przy pomocy yield return.
dalej

Możesz to przyspieszyć, używając innej optymalizacji kompilatora C #: dodaj metodę, SingleEnumerator GetEnumerator()która zwraca strukturę. Kompilator w języku C # użyje tej metody (sprawdza to za pomocą pisania kaczego) zamiast interfejsu i tym samym unika boksowania. Wiele wbudowanych kolekcji wykorzystuje tę sztuczkę, na przykład List . Uwaga: zadziała to tylko wtedy, gdy masz bezpośrednie odniesienie SingleSequence, jak w twoim przykładzie. Jeśli IEnumerable<>
umieścisz

5

IanG ma dobry post na ten temat , sugerując EnumerableFrom()jako nazwę (i wspomina, jak nazywają to Haskell i Rx Return). IIRC F # nazywa to również Return . F # Seqwzywa operatorasingleton<'T> .

Kuszące, jeśli jesteś przygotowany na koncentrację w języku C #, możesz to nazwać Yield[nawiązując do osób yield returnzaangażowanych w jego realizację].

Jeśli interesujesz się jego perfekcyjnymi aspektami, James Michael Hare ma również zwracany zero lub jeden post przedmiotów, co jest warte zeskanowania.


4

To może nie być nic lepszego, ale to trochę fajne:

Enumerable.Range(0, 1).Select(i => item);

To nie jest. To jest inne.
nawfal

Ewww. To bardzo dużo szczegółów, tylko po to, aby zmienić przedmiot w wyliczalny.
ToolmakerSteve

1
Jest to równoważne z użyciem maszyny Rube Goldberg do robienia śniadania. Tak, działa, ale przeskakuje przez 10 obręczy, aby się tam dostać. Taką prostą rzeczą może być wąskie gardło w zakresie wydajności, wykonywane w ciasnej pętli, która jest wykonywana miliony razy. W praktyce aspekt wydajności nie ma znaczenia w 99% przypadków, ale osobiście uważam, że to rażąca niepotrzebna nadwyżka.
enzi

4

Zgadzam się z komentarzami @ EarthEngine do oryginalnego postu, że „AsSingleton” to lepsza nazwa. Zobacz ten wpis w Wikipedii . Następnie z definicji singletonu wynika, że ​​jeśli wartość argumentu pustego zostanie przekazana jako argument, że „AsSingleton” powinien zwrócić IEnumerable z pojedynczą wartością null zamiast pustego IEnumerable, który rozstrzygnąłby if (item == null) yield break;debatę. Myślę, że najlepszym rozwiązaniem są dwie metody: „AsSingleton” i „AsSingletonOrEmpty”; gdzie w przypadku przekazania jako argumentu wartości null „AsSingleton” zwróci pojedynczą wartość null, a „AsSingletonOrEmpty” zwróci pustą IEnumerable. Lubię to:

public static IEnumerable<T> AsSingletonOrEmpty<T>(this T source)
{
    if (source == null)
    {
        yield break;
    }
    else
    {
        yield return source;
    }
}

public static IEnumerable<T> AsSingleton<T>(this T source)
{
    yield return source;
}

Wtedy byłyby mniej więcej analogiczne do metod rozszerzenia „First” i „FirstOrDefault” w IEnumerable, co wydaje się właściwe.


2

Najprostszym sposobem, który powiedziałbym, byłby new T[]{item};; nie ma do tego żadnej składni. Najbliższym odpowiednikiem, jaki mogę wymyślić, jest paramssłowo kluczowe, ale oczywiście wymaga ono dostępu do definicji metody i można go używać tylko z tablicami.


2
Enumerable.Range(1,1).Select(_ => {
    //Do some stuff... side effects...
    return item;
});

Powyższy kod jest użyteczny przy użyciu like

var existingOrNewObject = MyData.Where(myCondition)
       .Concat(Enumerable.Range(1,1).Select(_ => {
           //Create my object...
           return item;
       })).Take(1).First();

W powyższym fragmencie kodu nie ma sprawdzania pustego / zerowego i gwarantuje się, że zwrócony zostanie tylko jeden obiekt bez obawy wyjątków. Ponadto, ponieważ jest leniwy, zamknięcie nie zostanie wykonane, dopóki nie zostanie udowodnione, że nie ma żadnych istniejących danych spełniających kryteria.


Ta odpowiedź została automatycznie oznaczona jako „niska jakość”. Jak wyjaśniono w pomocy („Zwięzłość jest akceptowalna, ale lepsze są pełniejsze wyjaśnienia.”), Edytuj ją, aby powiedzieć PO, co robi źle, na czym polega Twój kod.
Sandra Rossi,

Widzę, że większość tej odpowiedzi, w tym część, na którą odpowiadam, została później edytowana przez kogoś innego. ale jeśli intencją drugim fragmencie jest dostarczenie wartość domyślną, jeśli MyData.Where(myCondition)jest pusta, to już możliwe (i prostsze) z DefaultIfEmpty(): var existingOrNewObject = MyData.Where(myCondition).DefaultIfEmpty(defaultValue).First();. Można to dodatkowo uprościć, var existingOrNewObject = MyData.FirstOrDefault(myCondition);jeśli chcesz, default(T)a nie wartość niestandardową.
BACON

0

Jestem trochę spóźniony na imprezę, ale i tak podzielę się swoją drogą. Mój problem polegał na tym, że chciałem powiązać ItemSource lub WPF TreeView z jednym obiektem. Hierarchia wygląda następująco:

Projekt> Działka (y)> Pokój (y)

Zawsze był tylko jeden projekt, ale nadal chciałem pokazać projekt w drzewie, bez konieczności przekazywania kolekcji zawierającej tylko jeden obiekt, jak sugerują niektórzy.
Ponieważ możesz przekazywać tylko obiekty IEnumerable jako ItemSource, postanowiłem uczynić moją klasę IEnumerable:

public class ProjectClass : IEnumerable<ProjectClass>
{
    private readonly SingleItemEnumerator<AufmassProjekt> enumerator;

    ... 

    public IEnumerator<ProjectClass > GetEnumerator() => this.enumerator;

    IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
}

I odpowiednio stwórz mojego Enumeratora:

public class SingleItemEnumerator : IEnumerator
{
    private bool hasMovedOnce;

    public SingleItemEnumerator(object current)
    {
        this.Current = current;
    }

    public bool MoveNext()
    {
        if (this.hasMovedOnce) return false;
        this.hasMovedOnce = true;
        return true;
    }

    public void Reset()
    { }

    public object Current { get; }
}

public class SingleItemEnumerator<T> : IEnumerator<T>
{
    private bool hasMovedOnce;

    public SingleItemEnumerator(T current)
    {
        this.Current = current;
    }

    public void Dispose() => (this.Current as IDisposable).Dispose();

    public bool MoveNext()
    {
        if (this.hasMovedOnce) return false;
        this.hasMovedOnce = true;
        return true;
    }

    public void Reset()
    { }

    public T Current { get; }

    object IEnumerator.Current => this.Current;
}

To chyba nie jest „najczystsze” rozwiązanie, ale dla mnie zadziałało.

EDYCJA
Aby podtrzymać zasadę pojedynczej odpowiedzialności, jak zauważył @Groo, stworzyłem nową klasę opakowań:

public class SingleItemWrapper : IEnumerable
{
    private readonly SingleItemEnumerator enumerator;

    public SingleItemWrapper(object item)
    {
        this.enumerator = new SingleItemEnumerator(item);
    }

    public object Item => this.enumerator.Current;

    public IEnumerator GetEnumerator() => this.enumerator;
}

public class SingleItemWrapper<T> : IEnumerable<T>
{
    private readonly SingleItemEnumerator<T> enumerator;

    public SingleItemWrapper(T item)
    {
        this.enumerator = new SingleItemEnumerator<T>(item);
    }

    public T Item => this.enumerator.Current;

    public IEnumerator<T> GetEnumerator() => this.enumerator;

    IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
}

Którego tak użyłem

TreeView.ItemSource = new SingleItemWrapper(itemToWrap);

EDYCJA 2
Poprawiłem błąd w MoveNext()metodzie.


SingleItemEnumerator<T>Klasa ma sens, ale co klasa „pojedynczy element IEnumerableo sobie” wydaje się to sprzeczne z zasadą jednolitego odpowiedzialność. Być może sprawia, że ​​przekazywanie go jest bardziej praktyczne, ale nadal wolę go owijać w razie potrzeby.
Groo,

0

Aby znaleźć się w rubryce „Niekoniecznie dobre rozwiązanie, ale nadal ... rozwiązanie” lub „Głupie sztuczki LINQ”, można połączyć Enumerable.Empty<>()z Enumerable.Append<>()...

IEnumerable<string> singleElementEnumerable = Enumerable.Empty<string>().Append("Hello, World!");

... lub Enumerable.Prepend<>()...

IEnumerable<string> singleElementEnumerable = Enumerable.Empty<string>().Prepend("Hello, World!");

Dwie ostatnie metody są dostępne od wersji .NET Framework 4.7.1 i .NET Core 1.0.

Jest to wykonalne rozwiązanie, jeśli jeden z nich naprawdę zdecydowani wykorzystaniem istniejących metod zamiast pisać własne, choć jestem niezdecydowany, czy jest to mniej lub bardziej wyraźne niż w Enumerable.Repeat<>()roztworze . Jest to zdecydowanie dłuższy kod (częściowo z powodu niemożności wnioskowania o parametrach typuEmpty<>() ) i tworzy jednak dwa razy więcej obiektów wyliczających.

Uzupełnienie tego „Czy wiesz, że te metody istnieją?” odpowiedź Array.Empty<>()może być zastąpiona Enumerable.Empty<>(), ale trudno argumentować, że sytuacja jest ... lepsza.


0

Niedawno zapytałem o to samo w innym poście ( Czy istnieje sposób na wywołanie metody C # wymagającej IEnumerable <T> z jedną wartością? ... z testem porównawczym ).

Chciałem, aby ludzie zatrzymujący się tutaj mogli zobaczyć krótkie porównanie testów porównawczych pokazane w tym nowym poście dla 4 podejść przedstawionych w tych odpowiedziach.

Wydaje się, że zwykłe wpisanie new[] { x }argumentów do metody jest najkrótszym i najszybszym rozwiązaniem.

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.