Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 228
Earlz Avatar asked Jan 12 '23 17:01

Earlz


1 Answers

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.

like image 93
Sergey Berezovskiy Avatar answered Jan 25 '23 03:01

Sergey Berezovskiy