Objetos XName y XNamespace atomizados (LINQ to XML)
Los objetos XName y XNamespace se atomizan; es decir, si contienen el mismo nombre completo, hacen referencia al mismo objeto. Esto genera ventajas de rendimiento para las consultas: cuando se compara si dos nombres atomizados son iguales, el lenguaje intermedio subyacente solo debe determinar si las dos referencias apuntan al mismo objeto. El código subyacente no debe hacer comparaciones de cadenas, lo que llevaría más tiempo.
Semántica de atomización
La atomización significa que si dos objetos XName tienen el mismo nombre local y se encuentran en el mismo espacio de nombres, comparten la misma instancia. De igual forma, si dos objetos XNamespace tienen el mismo URI de espacio de nombres, comparten la misma instancia.
Para que una clase habilite objetos atomizados, el constructor de la clase debe ser privado y no público. La razón es que si el constructor fuera público, podría crea un objeto no atomizado. Las clases XName y XNamespace implementan un operador de conversión implícita para convertir una cadena en XName o XNamespace. De esta forma, obtiene una instancia de estos objetos. No puede obtener una instancia mediante un constructor, ya que no se puede acceder a él.
XName y XNamespace también implementan los operadores de igualdad y desigualdad, que determinan si los dos objetos que se están comparando son referencias a la misma instancia.
Ejemplo: Creación de objetos y demostración de que los nombres idénticos comparten una instancia
El siguiente código crea algunos objetos XElement y muestra que nombres idénticos comparten la misma instancia.
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 ejemplo produce el siguiente resultado:
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 se ha mencionado anteriormente, la ventaja de los objetos atomizados es que el usuario utiliza uno de los métodos de eje que toman XName como parámetro, el método de eje solo debe determinar que los dos nombres hagan referencia a la misma instancia para seleccionar los elementos deseados.
El siguiente ejemplo pasa XName a la llamada del método Descendants, cuyo rendimiento mejora gracias al patrón de atomización.
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 ejemplo produce el siguiente resultado:
<C1>1</C1>
<C1>1</C1>