Udostępnij przez


Zatomizowane obiekty XName i XNamespace (LINQ to XML)

XName obiekty i XNamespaceatomizowane; oznacza to, że jeśli zawierają tę samą kwalifikowaną nazwę, odwołują się do tego samego obiektu. Daje to korzyści wydajnościowe dla zapytań: podczas porównywania dwóch zatomizowanych nazw pod względem równości, podstawowy kod pośredni ma jedynie za zadanie określić, czy dwa odwołania wskazują na ten sam obiekt. Kod źródłowy nie musi wykonywać porównań ciągów, co trwa dłużej.

Semantyka atomizacji

Atomizacja oznacza, że jeśli dwa XName obiekty mają taką samą nazwę lokalną i są w tej samej przestrzeni nazw, współużytkują to samo wystąpienie. W ten sam sposób, jeśli dwa XNamespace obiekty mają ten sam identyfikator URI przestrzeni nazw, współużytkują to samo wystąpienie.

Aby klasa umożliwiała atomizowane obiekty, konstruktor klasy musi być prywatny, a nie publiczny. Jest to spowodowane tym, że jeśli konstruktor był publiczny, można utworzyć nie atomizowany obiekt. Klasy XName i XNamespace implementują niejawny operator konwersji, aby przekonwertować ciąg na element XName lub XNamespace. W ten sposób uzyskujesz wystąpienie tych obiektów. Nie można uzyskać wystąpienia przy użyciu konstruktora, ponieważ konstruktor jest niedostępny.

XName i XNamespace również zaimplementowały operatory równości i nierówności, które określają, czy dwa porównywane obiekty są referencjami do tego samego wystąpienia.

Przykład: Twórz obiekty i pokaż, że identyczne nazwy współdzielą wystąpienie

Poniższy kod tworzy kilka XElement obiektów i pokazuje, że identyczne nazwy dzielą to samo wystąpienie.

var r1 = new XElement("Root", "data1");
XElement r2 = XElement.Parse("<Root>data2</Root>");

if ((object)r1.Name == (object)r2.Name)
    Console.WriteLine("r1 and r2 have names that refer to the same instance.");
else
    Console.WriteLine("Different");

XName n = "Root";

if ((object)n == (object)r1.Name)
    Console.WriteLine("The name of r1 and the name in 'n' refer to the same instance.");
else
    Console.WriteLine("Different");
Dim r1 As New XElement("Root", "data1")
Dim r2 As XElement = XElement.Parse("<Root>data2</Root>")

If DirectCast(r1.Name, Object) = DirectCast(r2.Name, Object) Then
    Console.WriteLine("r1 and r2 have names that refer to the same instance.")
Else
    Console.WriteLine("Different")
End If

Dim n As XName = "Root"

If DirectCast(n, Object) = DirectCast(r1.Name, Object) Then
    Console.WriteLine("The name of r1 and the name in 'n' refer to the same instance.")
Else
    Console.WriteLine("Different")
End If

Ten przykład generuje następujące wyniki:

r1 and r2 have names that refer to the same instance.
The name of r1 and the name in 'n' refer to the same instance.

Jak wspomniano wcześniej, zaletą atomizowanych obiektów jest to, że gdy używasz jednej z metod osi, które przyjmują XName jako parametr, metoda osi musi jedynie określić, że dwie nazwy odnosiły się do tego samego wystąpienia, aby wybrać żądane elementy.

Poniższy przykład przekazuje XName do wywołania metody Descendants, co ma lepszą wydajność ze względu na wzorzec atomizacji.

var root = new XElement("Root",
    new XElement("C1", 1),
    new XElement("Z1",
        new XElement("C1", 2),
        new XElement("C1", 1)
    )
);

var query = from e in root.Descendants("C1")
            where (int)e == 1
            select e;

foreach (var z in query)
    Console.WriteLine(z);
Dim root As New XElement("Root", New XElement("C1", 1), New XElement("Z1", New XElement("C1", 2), New XElement("C1", 1)))

Dim query = From e In root.Descendants("C1") Where CInt(e) = 1

For Each z In query
    Console.WriteLine(z)
Next

Ten przykład generuje następujące wyniki:

<C1>1</C1>
<C1>1</C1>