アトミック化された XName および XNamespace オブジェクト (LINQ to XML)
XName オブジェクトと XNamespace オブジェクトは "アトミック化" されています。つまり、同じ修飾名を含んでいる場合は、同じオブジェクトを参照します。 これによってクエリのパフォーマンスが向上します。これは、2 つのアトミック化された名前の等価性を比べる場合に、基になる中間言語が、2 つの参照が同じオブジェクトを指しているかどうかを判別するだけで済むためです。 基になるコードは、時間のかかることがある文字列比較を行う必要がありません。
アトミック化のセマンティクス
アトミック化とは、2 個の XName オブジェクトのローカル名が同じであり、これらのオブジェクトが同じ名前空間にある場合に、同じインスタンスを共有するという意味です。 同様に、2 個の XNamespace オブジェクトに同じ名前空間 URI がある場合も、これらのオブジェクトは同じインスタンスを共有します。
アトミック化されたオブジェクトをクラスに対して有効にするには、クラスのコンストラクターがパブリックではなく、プライベートであることが必要です。 その理由は、コンストラクターがパブリックであれば、アトミック化されていないオブジェクトを作成できるからです。 XName クラスと XNamespace クラスは暗黙的な変換演算子を実装して、文字列を XName または XNamespace に変換します。 この方法でこれらのオブジェクトのインスタンスを取得します。 コンストラクターにはアクセスできないため、コンストラクターを使用してインスタンスを取得することはできません。
XName と XNamespace では、等値演算子と非等値演算子も実装されます。これらの演算子では、比較する 2 個のオブジェクトが同じインスタンスを参照しているか判断されます。
例: オブジェクトを作成し、同じ名前でインスタンスを共有していることを示す
次のコードは 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 がある軸メソッドの 1 つを使用するときに、目的の要素を選択するために、軸メソッドが、2 つの名前が同じインスタンスを参照していることを判別するだけで済むことです。
次の例では、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>
.NET