So I've been diving into Linq to XML for the first time (I know, I'm behind on the times) and so far it's pretty cool. However, I came across this very confusing behavior.
I'm parsing the common .resx
format. In it, you have data
tags that have a value
and an optional comment
. Here is the code I tried at first:
var items = from str in doc.Root.Descendants("data")
select new ResourceValue
{
Name = str.Attribute("name").Value,
Value = str.Element("value").Value,
Comment=str.Element("comment").Value
};
Of course, where I get the .value
of the comment
element though, it throws a null reference exception.. Well, let's try again. I heard you can cast XElement to a string and it'll magically work. Let's try that
var items = from str in doc.Root.Descendants("data")
select new ResourceValue
{
Name = str.Attribute("name").Value,
Value = str.Element("value").Value,
Comment=str.Element("comment") as string
};
Oooh. This time I get a compiler error.
Cannot convert type 'System.Xml.Linq.XElement' to 'string' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
Well, that's odd.. Let's search stackoverflow. Lo and behold, I find a snippet that suggests this instead:
var items = from str in doc.Root.Descendants("data")
select new ResourceValue
{
Name = str.Attribute("name").Value,
Value = str.Element("value").Value,
Comment=(string)str.Element("comment")
};
Whoa. That works!? But, casting null
to string throws a null reference exception... doesn't it? I thought as string
was exactly for this situation!?
How does this work, and why can I do an explicit cast, but not an explicit as
cast?
str.Element("comment") as string
This checks if XElement
is a string. But it's not true - XElement
is not derived from string, so it is not a string. That's why you have error.
(string)str.Element("comment")
This is an overloaded operator, which gets Value
property internally:
public static explicit operator string(XElement element)
{
if (element == null)
return null;
return element.Value;
}
It first checks if operand is null
and just returns null
if so. That's why you don't have exception.
BTW there is interesting thing with these explicit casting operators - none of them will throw NullReferenceException
because they check element for null before accessing it's Value property. Even if element is null
and you are trying to get integer, then you will have ArgumentNullException
instead of NullReferenceException
. And if null
is acceptable value for type you are casting to (i.e. nullable types or string) then null
is returned without any exceptions. That's why using these explicit casting operators is much safer than accessing Value property.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With