ConvertAllSłyszałeś o metodzie ConvertAll, bo ja nie xD . Jak sama nazwa metody wskazuje ta metoda konwertuje wszystkie elementy kolekcji na inny typ danych. Zwykle do utworzenia nowej kolekcji używam pętli foreach. LINQ daje nam jednak alternatywę i krótszą składnie. Rodzi się jednak pytanie czy w ogóle ta metoda jest nam potrzebna, gdyż ten sam rezultat możemy otrzymyać używając metody Select
Zobaczmy w akcji metodę ConvertAll.
Oto jak metoda ConvertAll może utworzyć kolekcję napisów bazując na kolekcji obiektów.
var objects = new List<object>() {121,22.12,12.3f,'a',true,false};
List<string> stringresults = objects2.ConvertAll(x => Convert.ToString(x));
foreach (string res in stringresults)
Console.WriteLine(res);
Możemy także skonwertować wartości liczbowe i stringowe na wartości logiczne.
var objects2 = new List<object>() { 1, 0, 1, 1, 0, "true" };
List<bool> boolresults = objects2.ConvertAll(x => Convert.ToBoolean(x));
foreach (bool res in boolresults)
Console.WriteLine(res);
Jeśli mamy kolekcje dat w postaci napisów możemy zmienić je na obiekty DateTime używając metody ConvertAll.
var objects3 = new List<object>() { "1988-12-12", "2013-12-12 4:00" };
List<DateTime> Datetimeresults = objects3.ConvertAll(x => Convert.ToDateTime(x));
foreach (DateTime res in Datetimeresults)
Console.WriteLine(res);
Wszystkie te 3 przykłady łączy jeden element.
Metoda ConvertAll bazuje na liście elementów i nie jest metodą rozszerzeniową, ponieważ istnieje ona w .NET 2.0.
Jak zapewne zauważyłeś żaden z tych przykładów nie używa metody ToList(), ponieważ metoda ta zwraca obiekt List<T>.
Jest ona wadliwa i nie działa ona w każdym scenariuszu. Oczywiście wszyscy użytkownicy LINQ wiedzą, że do konwersji jednej kolekcji na drugą mamy metodę rozszerzeniową Select.
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
List<int> list1 = list.Select(x => 2 * x).ToList();
List<int> list2 = list.ConvertAll(x => 2 * x);
Select zdecydowanie wygrywa, jeśli logika konwersji obiektu jest bardziej złożona przykładowo możemy napotkać wartość “null”.
Zdecydowanie metoda ConvertAll kuleje trochę, ale dziwoląga “toList()” nie musimy pisać.
List<int?> list = new List<int?> { 1, 2, 3, 4, 5 ,null};
List<int> list1 = list.Where(x => x.HasValue).Select(x => 2 * x.Value).ToList();
List<int> list2 = list.Where(x => x.HasValue).ToList().ConvertAll(x => 2 * x.Value);
List<int> list3 = list.FindAll(x => x.HasValue).ConvertAll(x => x.Value * 2);
Widać jednak, że brakuje metodzie ConvertAll elastyczności nie mówiąc o fakcie, że wciąż bazujemy na listach.
Select w końcu zwraca kolekcję interfejsu IEnumerable<T>.
Podsumowując. Metoda ConvertAll operuje na liście i zwraca listę. Select natomiast jest zapytaniem, które zostanie wykonane, dopiero gdy będzie ono potrzebne. Jeśli nie potrzebujesz natychmiastowo wyniku to “Select” wygra w wykonywaniu programu.
Z drugiej strony, gdy metoda ConvertAll raz się wykona nie potrzebujesz już oryginalnej listy.
Metody ConvertAll może tworzyć klasy anonimowe, ale lepiej do tego używać metody select.
List<int?> list = new List<int?> { 1, 2, 3, 4, 5, null };
var list3 = list.FindAll(x => x.HasValue).ConvertAll(x => new { dwax = x + x,razdwax = x * 2 });
Console.WriteLine(list3.GetType());
var list4 = list.Where(x => x.HasValue).Select(x => new { dwax = x + x, razdwax = x * 2 });
Console.WriteLine(list4.GetType());
Console.ReadKey();
Jakoś typ List<AnomousType#1> brzmi dziwnie i wydaje się sprzeczny z założeniami LINQ jak Lazy Execution i interfejs IEnumerable.