原子化的 XName 和 XNamespace 对象 (LINQ to XML)

XNameXNamespace 对象进行了原子化;即,如果这两个对象包含相同的限定名,则它们将引用同一个对象。 这将提高查询性能:当比较两个原子化名称是否相等时,基础中间语言只需确定这两个引用是否指向同一个对象。 基础代码不必进行很耗费时间的字符串比较。

原子化语义

原子化是指如果两个 XName 对象具有相同的本地名称并且位于同一个命名空间中,则它们共享相同的实例。 同样,如果两个 XNamespace 对象具有相同的命名空间 URI,则它们共享同一个实例。

对于启用原子化对象的类,该类的构造函数必须是私有的,而不是公共的。 这是因为如果构造函数是公共的,则您可以创建非原子化对象。 XNameXNamespace 类实现一个隐式转换运算符,以将字符串转换为 XNameXNamespace。 这是获取这些对象的实例的方式。 不能通过使用构造函数来获得实例,因为构造函数是不可访问的。

XNameXNamespace 还实现相等运算符和不相等运算符,以确定进行比较的两个对象是否引用相同的实例。

示例:创建对象,并显示相同的名称共享实例

下面的代码创建一些 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>