Objetos XName e XNamespace atomizados (LINQ to XML)

XName e XNamespace os objetos são atomizados, ou seja, se contêm o mesmo nome qualificado, referem-se ao mesmo objeto. Isso gera benefícios de desempenho para consultas: quando você compara dois nomes atomizados para igualdade, a linguagem intermediária subjacente só precisa determinar se as duas referências apontam para o mesmo objeto. O código subjacente não precisa fazer comparações de cadeia de caracteres, o que levaria mais tempo.

Semântica de atomização

Atomização significa que, se dois XName objetos tiverem o mesmo nome local e estiverem no mesmo namespace, eles compartilharão a mesma instância. Da mesma forma, se dois XNamespace objetos tiverem o mesmo URI de namespace, eles compartilharão a mesma instância.

Para que uma classe habilite objetos atomizados, o construtor da classe deve ser privado, não público. Isso ocorre porque se o construtor fosse público, você poderia criar um objeto não atomizado. As XName classes e XNamespace implementam um operador de conversão implícito para converter uma cadeia de caracteres em um XName ou XNamespace. É assim que você obtém uma instância desses objetos. Você não pode obter uma instância usando um construtor, porque o construtor é inacessível.

XName e XNamespace também implementam os operadores de igualdade e desigualdade, que determinam se os dois objetos a serem comparados são referências à mesma instância.

Exemplo: Criar objetos e mostrar que nomes idênticos compartilham uma instância

O código a seguir cria alguns XElement objetos e demonstra que nomes idênticos compartilham a mesma instância.

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

Este exemplo produz a seguinte saída:

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.

Como mencionado anteriormente, o benefício dos objetos atomizados é que, quando você usa um dos métodos axis que tomam um XName como parâmetro, o método axis só precisa determinar que dois nomes fazem referência à mesma instância para selecionar os elementos desejados.

O exemplo a seguir passa um XName para a chamada do método Descendants, o que melhora o desempenho graças ao padrão de atomização.

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

Este exemplo produz a seguinte saída:

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