Oggetti XName e XNamespace atomizzati (LiNQ to XML)
Gli oggetti XName e XNamespace sono atomizzati, ovvero, se contengono lo stesso nome completo fanno riferimento allo stesso oggetto. Questo offre vantaggi a livello di prestazioni per le query: quando si confrontano due nomi atomizzati per verificarne l'uguaglianza, il linguaggio intermedio sottostante deve determinare solo se i due riferimenti puntano allo stesso oggetto. Il codice sottostante non deve eseguire confronti tra stringhe, che richiederebbero più tempo.
Semantica di atomizzazione
Atomizzazione significa che se due oggetti XName hanno lo stesso nome locale e si trovano nello stesso spazio dei nomi, condividono la stessa istanza. Analogamente, se due oggetti XNamespace hanno lo stesso URI dello spazio dei nomi, condividono la stessa istanza.
Affinché una classe consenta gli oggetti atomizzati, il costruttore per la classe deve essere privato, non pubblico. Se il costruttore fosse pubblico, sarebbe possibile creare un oggetto non atomizzato. Le classi XName e XNamespace implementano un operatore di conversione implicita per la conversione di una stringa in un oggetto XName o XNamespace. In questo modo è possibile ottenere un'istanza di questi oggetti. Non è possibile ottenere un'istanza tramite un costruttore, in quanto il costruttore è inaccessibile.
XName e XNamespace implementano anche gli operatori di uguaglianza e di disuguaglianza, che determinano se i due oggetti confrontati sono riferimenti alla stessa istanza.
Esempio: Creare oggetti e mostrare che nomi identici condividono un'istanza
Nel codice seguente vengono creati alcuni oggetti XElement e viene dimostrato che i nomi identici condividono la stessa istanza.
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
Nell'esempio viene prodotto l'output seguente:
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.
Come illustrato in precedenza, il vantaggio degli oggetti atomizzati consiste nel fatto che quando si usa uno dei metodi dell'asse che accettano XName come parametro, il metodo dell'asse deve determinare solo che due nomi fanno riferimento alla stessa istanza per selezionare gli elementi desiderati.
Nell'esempio seguente viene passato un oggetto XName alla chiamata al metodo Descendants, le cui prestazioni sono quindi migliori grazie al modello di atomizzazione.
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
Nell'esempio viene prodotto l'output seguente:
<C1>1</C1>
<C1>1</C1>