Czy istnieje wspólny sposób przekazywania pojedynczego elementu typu T
do 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 Array
i 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<T>
/// 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<T> consisting of a single item. </returns>
public static IEnumerable<T> Yield<T>(this T item)
{
yield return item;
}
}
źródło
if (item == null) yield break;
teraz przestajesz przekazywać wartości zerowe, a także korzystać z (trywialnego) wzorca obiektów zerowychIEnumerable
. (foreach (var x in xs)
radzi sobie z pustą,xs
dobrze). Nawiasem mówiąc, ta funkcja jest jednostką monadyczną dla listy monadIEnumerable<T>
, a biorąc pod uwagę festiwal miłosny monad w Microsoft, jestem zaskoczony, że coś takiego nie znajduje się w ramach.AsEnumerable
ponieważ wbudowane rozszerzenie o tej nazwie już istnieje . (GdyT
implementujeIEnumerable
npstring
..)Yield
? Nic nie przebije zwięzłości.left==null
czeku 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, żenew T[] { null }
to nie to samo, conew T[] {}
pewnego dnia może być konieczne ich rozróżnienie.Odpowiedzi:
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.
źródło
myDict.Keys.AsEnumerable()
gdziemyDict
był typuDictionary<CheckBox, Tuple<int, int>>
. Po zmianie nazwy metody rozszerzenia naSingleItemAsEnumerable
wszystko 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?dictionary.Values
zacząć. Zasadniczo nie jest jasne, co się dzieje, ale sugeruję, aby rozpocząć nowe pytanie na ten temat.Cóż, jeśli metoda oczekuje
IEnumerable
, że musisz przekazać coś, co jest listą, nawet jeśli zawiera tylko jeden element.przechodzący
jak sądzę, argument powinien wystarczyć
źródło
W C # 3.0 możesz użyć klasy System.Linq.Enumerable:
Spowoduje to utworzenie nowego IEnumerable, który zawiera tylko twój element.
źródło
new[]{ item }
siebie, pomyślałem, że to ciekawe rozwiązanie.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:
kod klienta jest wtedy
item.ToEnumerable()
.źródło
ToEnumerable
uniknąć bałaganuSystem.Linq.Enumerable.AsEnumerable
ToEnumerable
metoda rozszerzenia dlaIObservable<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.Ta metoda pomocnicza działa dla przedmiotu lub wielu.
źródło
params
budowaniu tablicy, więc wynikowy kod wygląda czysto. Nie zdecydowałem, czy podoba mi się to bardziej, czy mniej niż wnew T[]{ item1, item2, item3 };
przypadku wielu przedmiotów.Jestem trochę zaskoczony, że nikt nie zasugerował nowego przeciążenia metody argumentem typu T, aby uprościć interfejs API klienta.
Teraz twój kod klienta może po prostu to zrobić:
lub z listą:
źródło
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.)Albo (jak już powiedziano)
lub
Na marginesie, ostatnia wersja może być również przyjemna, jeśli chcesz mieć pustą listę anonimowych obiektów, np
źródło
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:
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 )
źródło
.AsEnumerable()
. TablicaYourType[]
już implementujeIEnumerable<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.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.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ę.
Które można wykorzystać w następujący sposób:
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
=Rx
dlaIEnumerable
.Możesz znaleźć zarówno Rx, jak i Ix na CodePlex .
źródło
Jest to 30% szybsze niż
yield
lub wEnumerable.Repeat
przypadku użycia zforeach
powodu optymalizacji kompilatora C # i tej samej wydajności w innych przypadkach.w tym teście:
źródło
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 pomocyyield return
.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 odniesienieSingleSequence
, jak w twoim przykładzie. JeśliIEnumerable<>
IanG ma dobry post na ten temat , sugerując
EnumerableFrom()
jako nazwę (i wspomina, jak nazywają to Haskell i RxReturn
).IIRC F # nazywa to również Return. F #Seq
wzywa operatorasingleton<'T>
.Kuszące, jeśli jesteś przygotowany na koncentrację w języku C #, możesz to nazwać
Yield
[nawiązując do osóbyield return
zaangaż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.
źródło
To może nie być nic lepszego, ale to trochę fajne:
źródło
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:Wtedy byłyby mniej więcej analogiczne do metod rozszerzenia „First” i „FirstOrDefault” w IEnumerable, co wydaje się właściwe.
źródło
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ć, jestparams
słowo kluczowe, ale oczywiście wymaga ono dostępu do definicji metody i można go używać tylko z tablicami.źródło
Powyższy kod jest użyteczny przy użyciu like
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.
źródło
MyData.Where(myCondition)
jest pusta, to już możliwe (i prostsze) zDefaultIfEmpty()
: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ą.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:
I odpowiednio stwórz mojego Enumeratora:
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ń:
Którego tak użyłem
EDYCJA 2
Poprawiłem błąd w
MoveNext()
metodzie.źródło
SingleItemEnumerator<T>
Klasa ma sens, ale co klasa „pojedynczy elementIEnumerable
o 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.Aby znaleźć się w rubryce „Niekoniecznie dobre rozwiązanie, ale nadal ... rozwiązanie” lub „Głupie sztuczki LINQ”, można połączyć
Enumerable.Empty<>()
zEnumerable.Append<>()
...... lub
Enumerable.Prepend<>()
...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ąpionaEnumerable.Empty<>()
, ale trudno argumentować, że sytuacja jest ... lepsza.źródło
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.źródło