Statisch gecompileerde query's (LINQ naar XML)

Een van de belangrijkste prestatievoordelen van LINQ naar XML, in vergelijking met XmlDocumentXML, is dat query's in LINQ naar XML statisch worden gecompileerd, terwijl XPath-query's tijdens runtime moeten worden geïnterpreteerd. Deze functie is ingebouwd in LINQ naar XML, dus u hoeft geen extra stappen uit te voeren om er gebruik van te maken, maar het is handig om het onderscheid te begrijpen bij het kiezen tussen de twee technologieën. In dit artikel wordt het verschil uitgelegd.

Statisch gecompileerde query's versus XPath

In het volgende voorbeeld ziet u hoe u de afstammende elementen met een opgegeven naam en met een attribuut met een opgegeven waarde kunt ophalen. De equivalente XPath-expressie is //Address[@Type='Shipping'].

XDocument po = XDocument.Load("PurchaseOrders.xml");

IEnumerable<XElement> list1 =
    from el in po.Descendants("Address")
    where (string)el.Attribute("Type") == "Shipping"
    select el;

foreach (XElement el in list1)
    Console.WriteLine(el);
Dim po = XDocument.Load("PurchaseOrders.xml")

Dim list1 = From el In po.Descendants("Address")
            Where el.@Type = "Shipping"

For Each el In list1
    Console.WriteLine(el)
Next

De query-expressie in dit voorbeeld wordt opnieuw geschreven door de compiler naar op methoden gebaseerde querysyntaxis. Het volgende voorbeeld, dat is geschreven in querysyntaxis op basis van een methode, produceert dezelfde resultaten als de vorige:

XDocument po = XDocument.Load("PurchaseOrders.xml");

IEnumerable<XElement> list1 =
    po
    .Descendants("Address")
    .Where(el => (string)el.Attribute("Type") == "Shipping");

foreach (XElement el in list1)
    Console.WriteLine(el);
Dim po = XDocument.Load("PurchaseOrders.xml")

Dim list1 As IEnumerable(Of XElement) = po.Descendants("Address").Where(Function(el) el.@Type = "Shipping")

For Each el In list1
   Console.WriteLine(el)
Next

De Where methode is een extensiemethode. Zie Extensiemethoden (C#-programmeerhandleiding) voor meer informatie. Omdat Where dit een extensiemethode is, wordt de bovenstaande query gecompileerd alsof deze als volgt is geschreven:

XDocument po = XDocument.Load("PurchaseOrders.xml");

IEnumerable<XElement> list1 =
    System.Linq.Enumerable.Where(
        po.Descendants("Address"),
        el => (string)el.Attribute("Type") == "Shipping");

foreach (XElement el in list1)
    Console.WriteLine(el);
Dim po = XDocument.Load("PurchaseOrders.xml")

Dim list1 = Enumerable.Where(po.Descendants("Address"), Function(el) el.@Type = "Shipping")

For Each el In list1
    Console.WriteLine(el)
Next

Dit voorbeeld produceert precies dezelfde resultaten als de vorige twee voorbeelden. Dit illustreert het feit dat query's effectief worden gecompileerd in statisch gekoppelde methode-aanroepen. Dit verbetert de prestaties in combinatie met de uitgestelde uitvoeringssemantiek van iterators. Zie Uitgestelde uitvoering en luie evaluatie voor meer informatie over de uitgestelde uitvoeringssemantiek van iterators.

Opmerking

Deze voorbeelden zijn representatief voor de code die de compiler kan schrijven. De daadwerkelijke implementatie kan enigszins afwijken van deze voorbeelden, maar de prestaties zijn hetzelfde als of vergelijkbaar met deze voorbeelden.

XPath-expressies uitvoeren met XmlDocument

In het volgende voorbeeld wordt XmlDocument gebruikt om dezelfde resultaten te bereiken als in de vorige voorbeelden.

XmlReader reader = XmlReader.Create("PurchaseOrders.xml");
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNodeList nl = doc.SelectNodes(".//Address[@Type='Shipping']");
foreach (XmlNode n in nl)
    Console.WriteLine(n.OuterXml);
reader.Close();
Dim reader = Xml.XmlReader.Create("PurchaseOrders.xml")
Dim doc As New Xml.XmlDocument()
doc.Load(reader)
Dim nl As Xml.XmlNodeList = doc.SelectNodes(".//Address[@Type='Shipping']")
For Each n As Xml.XmlNode In nl
    Console.WriteLine(n.OuterXml)
Next
reader.Close()

Deze query retourneert dezelfde uitvoer als de voorbeelden die LINQ naar XML gebruiken; het enige verschil is dat LINQ naar XML de afgedrukte XML inspringt, terwijl XmlDocument dat niet doet.

De XmlDocument methode presteert echter meestal niet zo goed als LINQ naar XML, omdat de SelectNodes methode het volgende moet doen telkens wanneer deze wordt aangeroepen:

  • Parseert de tekenreeks die de XPath-expressie bevat, waardoor de tekenreeks wordt opgesplitst in tokens.
  • Valideer de tokens om ervoor te zorgen dat de XPath-expressie geldig is.
  • Vertaal de expressie naar een interne expressieboom.
  • Doorloop de knooppunten en selecteer de juiste knooppunten voor de resultatenset op basis van de evaluatie van de uitdrukking.

Dit is aanzienlijk meer dan het werk dat door de bijbehorende LINQ naar XML-query wordt uitgevoerd. Het specifieke prestatieverschil varieert voor verschillende typen query's, maar in het algemeen werken LINQ naar XML-query's minder en presteren ze daarom beter dan het evalueren van XPath-expressies met behulp van XmlDocument.