LINQ to XML, cz. 3 - Zapytania - kontynuacja
Oczywiście warunki w klauzuli "where" mogą być złożone. Przykładowo możemy poszerzyć warunek w powyższym zapytaniu tak aby dodatkow zawężyć wynik tylko do tych węzłów gdzie godzina wylotu lub przylotu jest poźniejsza niż czwarta. Oto przykład takiego zapytania:
var elements =
from el in xDoc.Descendants()
where (string)el.Attribute("kod-lotniska") == "LHR" &&
((DateTime)el.Attribute("data")).Hour > 4
select el;
Zapytanie to jest interesujące jeszcze z jednego powodu - mianowicie okazuje się, że atrybut (obiekt klasy XAttribute) może być rzutowany zarówno do typu string jak i do typu DateTime. Odpowiadaja za to jawne (ang. explicit) operatory do konwersji typów. Są one zdefiniowane na klasach XAttribute oraz XElement. Więcej o jawnych operatorach kowersji typów można znaleźć w MSDN pod poniższym linkiem: http://msdn.microsoft.com/en-us/library/xhbhezf4.aspx. Lista typów dla których zdefiniowane są jawne operatory konwersji znajdują się tutaj dla klasy XElement http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.op_explicit.aspx a tutaj dla klasy XAttribute http://msdn.microsoft.com/en-us/library/system.xml.linq.xattribute.op_explicit.aspx. Na potrzeby tego kursu wystarczy chyba tylko wiedzieć, że jawne operatory kownersji umożliwiają rzutowanie nawet w przypadkach gdy typ docelowy nie jest typem pochodnym od typu źródłowego.
Zastosowanie jawnych operatorów konwersji typów przynosi następujące korzyści:
- skraca zapytanie i zwiększa jego przejrzystość
- pomaga kontrolować poprawność semantyczną dokumentu (oznacza to, że jeżeli rzutowana wartość nie jest zgodna z typem docelowym to zostanie wyrzucony wyjątek)
- pomaga uniknąć wyjątków typu NullReferenceException związanymi z brakiem wyszukiwanego elementu lub atrybutu
Pierwsze dwa punkty są raczej jasne, natomiast nad trzeci chyba nieszczególnie. Załóżmy przez chwilę, że zamiast używać operatora konwersji będziemy "dobierać" się do wartości elementu używając właściwości .Value. Nasze zapytanie wyglądałoby wtedy następująco:
var elements =
from el in xDoc.Elements("wycieczka").Elements("segment").Elements()
where el.Attribute("kod-lotniska").Value == "LHR"
select el;
Zapytanie działa ale co by się stało gdyby atrybutu @kod-lotniska nie było? W takim przypadku wywołanie el.Attribute("kod-lotniska") zwróciłoby wartość null. W efekcie próba pobrania wartości atrybutu za pomocą właściwości .Value skończyłaby się wyjątkiem NullReferenceException. Operator konwersji pozwala uniknąć tego rodzaju sytuacji. Jest to bardzo poręczne, ponieważ w praktyce często można spotkać sie z dokumentami Xmlowymi zawierającymi węzły lub atrybuty, które mogą występować opcjonalnie.

