Поделиться через


Объекты Atomized XName и XNamespace (LINQ to XML)

Объекты XName и XNamespace являются атомарными; иными словами, если они имеют идентичное полное имя, они ссылаются на один и тот же объект. Это дает преимущества производительности для запросов: при сравнении двух атомизованных имен для равенства базовый промежуточный язык должен определить, указывает ли два ссылки на один и тот же объект. Базовый код не должен выполнять сравнения строк, что займет больше времени.

Семантика атомизации

Atomization означает, что если два XName объекта имеют одинаковое локальное имя, и они в одном пространстве имен, они используют один и тот же экземпляр. Аналогично, если два объекта XNamespace имеют идентичный идентификатор URI пространства имен, то они совместно используют один и тот же экземпляр.

Чтобы разрешить создание атомарных объектов класса, необходимо, чтобы конструктор класса был закрытым, а не открытым. Это требование основано на том, что если бы конструктор был открытым, можно было бы создавать неатомарные объекты. Классы XName и XNamespace реализуют неявный оператор преобразования строки в объект XName или XNamespace. Экземпляры этих объектов могут быть получены только таким способом. Невозможно получить экземпляр с помощью конструктора, так как конструктор недоступен.

XName а XNamespace также реализуйте операторы равенства и неравенства, определяющие, являются ли сравниваемые два объекта ссылками на один и тот же экземпляр.

Пример. Создание объектов и отображение того, что идентичные имена совместно используют экземпляр

Следующий код создает объекты XElement и демонстрирует, что идентичные имена совместно используют один и тот же экземпляр.

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

В примере получается следующий вывод.

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.

Как отмечалось выше, преимущество атомарных объектов заключается в том, что при использовании одного из методов оси, принимающих в качестве параметра XName, этому методу оси для выбора необходимых элементов достаточно определить, что два имени совместно используют один и тот же экземпляр.

В следующем примере объект XName передается при вызове метода Descendants, производительность которого выше за счет использования атомизации.

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

В примере получается следующий вывод.

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