Why can I use (string) but not "as string" in Linq to XML queries?

c#, linq, linq-to-xml, xml

Solution

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.

Problem

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?

Original source

Related problems