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”.

Exception

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);
Odpowiednikiem  składni Where() dla ConvertAll byłaby metoda “FindAll”.
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.