Why do null explicit cast LINQ statements throw invalid format exceptions when empty?

First, I know that this question can be answered with a simple answer, that an empty string is not a null value. Also, I only recently discovered casting operators earlier this year through another stack question and didn't have much experience with them. However, the reason this is not so simple is that these casting operators, combined with the null coalescing operator, are declared as an elegant solution for solving error conditions such as missing elements or attributes in LINQ expressions. I started using the approach described by ScottH in “Improving LINQ Code Odor ...” and ScottGu's “Null Coalescing Operator (and Using It with LINQ)” as a means of protecting against invalid / missing data in a compressed and semi-elegant style. From what I can put together, this is apparently one of the motivations for putting all the overloaded roles in LINQ classes first.

Thus, in my opinion, using a case with a missing value is not all that differs from how to deal with blank and related articles, this approach is considered a good way to deal with such situations.

Scenario:

int length = (int?)elem.Attribute("Length") ?? 0; 

If the @Length attribute is missing, the cast results in a null value, and the value? operator returns 0;

If the @Length attribute exists, but it is empty, it internally branches into int.tryparse and throws a format exception. Of course, for my use, I would like it to not be and just return zero so that I can continue to use this approach in my already somewhat confusing LINQ code.

Ultimately, it’s not so much that I can’t come up with a solution, but moreover, I’m interested to hear if there is an obvious approach that I have missed, or if someone has a good perspective as to why the value scenario was missing considered, but the script with an empty value was not.

Edit

There seem to be a few key points that I should try and highlight:

  • Related articles are MS employees who I admire and seek guidance. These articles seem to suggest (or at least pay attention to) an improved / alternative approach for working with optional values

  • In my case, optional values ​​sometimes come in the form of missing elements or attributes, but also come in the form of empty elements or values

  • The described approach works as expected for missing values, but with an error for empty values

  • The code that follows the approach described seems to protect against the absence of optional values, but is actually fragile and breaks in a specific case. This is the appearance of protection when in fact you are still at risk that bothers me.

  • This can be highlighted by indicating that both related examples do not work with runtime exception if the target element exists but is empty

  • Finally, it seems that the main approach - the described approach works fine when you have a contract (possibly through a scheme) that ensures that the element or attribute is never empty, but in cases where this contract does not exist, this approach is invalid and alternative is needed

+6
c # linq linq-to-sql
source share
2 answers

I agree with the behavior; if I do not have an id attribute / element, then I am glad to consider it as null, but if it exists , but does not parse , this is different - and an empty string works for very few types. You will need to do this manually or you can add an extension method to XAttribute , etc .:

 public static int? ParseInt32(this XAttribute attrib) { if(attrib != null && string.IsNullOrEmpty(attrib.Value)) return null; return (int?)attrib; } 

Note. I use listing internally, as it is just for int , a .Parse would be a bad example for DateTime , etc., which uses a different format in xml, which is processed manually.

+3
source share

Regarding the workaround approach, I have already built the extension method below. I did not think of the method described by Marc that fixes the problem with a nullable int and still use? operator to specify the default value. Very creative and allows X ?? Y to continue using.

I think that in the end, I probably prefer the Marc approach, because it preserves the consistent pattern in my assignment statements and does not introduce the syntax confusion that the TryParseInt call caused, because it looks too much like you parse -1 or something default / fallback value.

  elem.Attribute("ID").TryParseInt(-1) /// <summary> /// Parses an attribute to extract an In32 value and falls back to the defaultValue should parsing fail /// </summary> /// <param name="defaultValue">The value to use should Int32.TryParse fail</param> /// <returns>The parsed or default integer value</returns> public static int TryParseInt(this XAttribute attr, int defaultValue) { int result; if (!Int32.TryParse((string)attr, out result)) { // When parsing fails, use the fallback value result = defaultValue; } return result; } 
+1
source share

All Articles