Coraz częściej w projektach zaczynam używać LINQ i zaczynam dostrzegać zalety. Nie dość, że można w ten sposób trochę pisania kodu oraz zyskać na przejrzystości. Poniżej zamieszczę parę przykładów, w których pomału przerzucam się na LINQ. W celach demonstracyjnych stwórzmy klasę Person, której obiekty będą reprezentowały osoby.
class Person : IComparable
{
public Person(string name, string surname, int age, bool married)
{
this.Name = name;
this.Surname = surname;
this.Age = age;
this.Married = married;
}
public Person()
{}
public string Name { get; set; }
public string Surname { get; set; }
public int Age { get; set; }
public bool Married { get; set; }
public int CompareTo(object obj)
{
Person otherPerson = obj as Person;
if (otherPerson != null)
return Surname.CompareTo(otherPerson.Surname) == 0 ? (Name.CompareTo(otherPerson.Name) == 0
? Age.CompareTo(otherPerson.Age)
: Name.CompareTo(otherPerson.Name)) : Surname.CompareTo(otherPerson.Surname);
else
throw new ArgumentException("Object is not a Person");
}
}
Jak widać klasa ma cztery własności:
- imię,
- nazwisko,
- wiek,
- informację, czy ktoś ma żonę lub męża.
Dodatkowo w klasie zostały zdefiniowane dwa konstruktory. Jeden domyślny, a drugi przypisujący wartości do wcześniej wspomnianych własności. Klasa również implementuje interfejs IComparable, ale o tym później.
Pierwszy scenariusz, w którym chcę zademonstrować wyższość LINQ nad klasycznym podejściem jest sytuacja w której należy wybrać obiekty spełniające określone kryteria. Dla przykładu załóżmy, że należy wybrać obiekty, które spełniają następujące warunki:
- osoby muszą mieć więcej niż 20 lat,
- osoby są żonate, bądź też zamężne.
Standardowo takie problem rozwiązuje się budując pętlę, która przechodzi przez wszystkie elementy i sprawdza, czy dany obiekt spełnia zadane kryteria. W sytuacji, gdy kryteria zostają spełnione dany obiekt kopiuje się do docelowej listy. Powyższy algorytm prezentuje poniższy kod:
List<Person> filtered = new List<Person>();
foreach (Person pearson in people)
{
if (pearson.Age > 20 && pearson.Married)
{
filtered.Add(pearson);
}
}
To samo można zrobić teoretycznie za pomocą jednej linijki kodu przy pomocy LINQ:
var filtered2 = from currentPearson in people
where currentPearson.Age > 20 && currentPearson.Married
select currentPearson;
Wydaje mi się, że rozwiązanie za pomocą LINQ jest o wiele bardziej czytelniejsze i łatwiejsze do późniejszego utrzymania.
Kolejny przykład jest modyfikacją obecnego. Dodajmy do przykładu, że chcemy pobrać tylko dwa pierwsze elementy. W klasycznym podejściu można zrobić to w następujący sposób:
List<Person> filtered = new List<Person>();
for (int i = 0; i < people.Count && filtered.Count < 2; i++)
{
if (people[i].Age > 20 && people[i].Married)
{
filtered.Add(people[i]);
}
}
W LINQ kod ten można zastąpić w następujący sposób:
var filtered2 = people.Where(p => p.Age > 20 && p.Married).Take(2);
I ponownie można zauważyć, że rozwiązanie LINQ jest bardziej proste i czytelniejsze.
W moim kodzie dość często pojawia się również potrzeba pobrania pierwszego elementu z kolekcji. W klasyczny sposób należy sprawdzić czy kolekcja została poprawnie zainicjalizowana oraz czy zawiera jakieś elementy. Dopiero potem można pobrać interesujący nas element.
Person person1;
if (people != null && people.Count > 0)
{
person1 = people[0];
}
W LINQ zadanie to jest banalne:
Person person2 = people.FirstOrDefault();
Ostatni przykład związany jest z sortowaniem. Klasycznie, aby posortować kolekcję należy w obiekcie zaimplementować interfejs IComparable i użyć metody Sort(). Implementację tego interfejsu można znaleźć na początku artykułu w miejscu gdzie przedstawiona klasa Person. Rozwiązanie jest stosunkowo proste, jeśli chce się posortować listę zawsze w ten sam sposób. Ale już w sytuacji, kiedy chcemy, aby była możliwość sortowania na różne sposoby sprawa się już trochę komplikuje.
people.Sort();
Sprawa wygląda o wiele bardziej optymistycznie w LINQ. Wystarczy tylko jedna linijka, aby osiągnąć to co dała nam implementacja interfejsu IComparable:
var sortedPeople = people.OrderBy(u => u.Surname).ThenBy(u => u.Name).ThenBy(u => u.Age);
Dodatkowo, jeśli chcemy w następnej linijce chcemy zmienić kolejność sortowania to nic nie stoi, ku temu na przeszkodzie.
sortedPeople = people.OrderBy(u => u.Surname).ThenBy(u => u.Name).ThenByDescending(u => u.Age);
Jak również nie ma przeszkód, aby przed sortowanie zawęzić wyniki i wybrać tylko te elementy, które nas interesują:
sortedPeople = people.Where(p => p.Age > 20 && p.Married).OrderBy(u => u.Surname) .ThenBy(u => u.Name).ThenByDescending(u => u.Age);

Cześć,
potrzebuję dopasować zapytanie w linq do wzorca regularnego mam coś takiego ale mi to nie działa…
Regex rgx = new Regex(pattern);
string passtru = db.Users.Where(s => s.login == log && s.password.rgx.IsMatch(pattern)).FirstOrDefault().name;
jakaś podpowiedź?
Łap przykład:
var names = new string[] { „Michal”, „Adam”};
string pattern = „M*”;
Regex rgx = new Regex(pattern);
var nameOnM = names.Where(name => rgx.IsMatch(name)).FirstOrDefault();
Mimo że lubię LINQ, uważam że należy używać go z głową i rozumieć jak działa.
Ja w firmie znajduję np. takie kwiatki:
private int Get(IList lista)
{
var filteredItems = lista.Where(item => CanSomething(item));
var value = filteredItems.Count() > 0 ? filteredItems.First().Value : 0;
return paymentValue;
}
A można przecież napisać też czytelnie i wydajniej (bez LINQ) :
private int Get(IList lista)
{
for (var i = 0; i < lista.Count; i++)
{
if (CanSomething(lista[i]))
return lista[i].Value;
}
return 0;
}