Pre-Atomization of XName Objects (LINQ to XML)
One way to improve performance in LINQ to XML is to pre-atomize XName objects. Pre-atomization means that you assign a string to an XName object before you create the XML tree by using the constructors of the XElement and XAttribute classes. Then, instead of passing a string to the constructor, which would use the implicit conversion from string to XName, you pass the initialized XName object.
This improves performance when you create a large XML tree in which specific names are repeated. To do this, you declare and initialize XName objects before you construct the XML tree, and then use the XName objects instead of specifying strings for the element and attribute names. This technique can yield significant performance gains if you are creating a large number of elements (or attributes) with the same name.
You should test pre-atomization with your scenario to decide if you should use it.
Example
The following example demonstrates this.
XName Root = "Root";
XName Data = "Data";
XName ID = "ID";
XElement root = new XElement(Root,
new XElement(Data,
new XAttribute(ID, "1"),
"4,100,000"),
new XElement(Data,
new XAttribute(ID, "2"),
"3,700,000"),
new XElement(Data,
new XAttribute(ID, "3"),
"1,150,000")
);
Console.WriteLine(root);
This example produces the following output:
<Root>
<Data ID="1">4,100,000</Data>
<Data ID="2">3,700,000</Data>
<Data ID="3">1,150,000</Data>
</Root>
The following example shows the same technique where the XML document is in a namespace:
XNamespace aw = "https://www.adventure-works.com";
XName Root = aw + "Root";
XName Data = aw + "Data";
XName ID = "ID";
XElement root = new XElement(Root,
new XAttribute(XNamespace.Xmlns + "aw", aw),
new XElement(Data,
new XAttribute(ID, "1"),
"4,100,000"),
new XElement(Data,
new XAttribute(ID, "2"),
"3,700,000"),
new XElement(Data,
new XAttribute(ID, "3"),
"1,150,000")
);
Console.WriteLine(root);
This example produces the following output:
<aw:Root xmlns:aw="https://www.adventure-works.com">
<aw:Data ID="1">4,100,000</aw:Data>
<aw:Data ID="2">3,700,000</aw:Data>
<aw:Data ID="3">1,150,000</aw:Data>
</aw:Root>
The following example is more similar to what you will likely encounter in the real world. In this example, the content of the element is supplied by a query:
XName Root = "Root";
XName Data = "Data";
XName ID = "ID";
DateTime t1 = DateTime.Now;
XElement root = new XElement(Root,
from i in System.Linq.Enumerable.Range(1, 100000)
select new XElement(Data,
new XAttribute(ID, i),
i * 5)
);
DateTime t2 = DateTime.Now;
Console.WriteLine("Time to construct:{0}", t2 - t1);
The previous example performs better than the following example, in which names are not pre-atomized:
DateTime t1 = DateTime.Now;
XElement root = new XElement("Root",
from i in System.Linq.Enumerable.Range(1, 100000)
select new XElement("Data",
new XAttribute("ID", i),
i * 5)
);
DateTime t2 = DateTime.Now;
Console.WriteLine("Time to construct:{0}", t2 - t1);