Question

I'm building an XML Deserializer for a project and I run across this type of code situation fairly often:

var myVariable = ParseNDecimal(xml.Element("myElement")) == null ? 
                 0 : ParseNDecimal(xml.Element("myElement")).Value;

Is there a better way to write this statement?

EDIT : Perhaps I should have clarified my example as I do have a helper method to parse the string into a decimal.

Was it helpful?

Solution

You can use extension method:

public static T TryGetValue<T>( this XmlElement element ) {
    if ( null == element ) return default(T);
    return (T)element.Value;
}
...
...
var myVariable = xml.Element("myElement").TryGetValue<decimal>();

EDIT:

The "universal" solution:

static class Program {
    static void Main() {
        var xmlDecimal = new XElement( "decimal" );
        xmlDecimal.Value = ( 123.456m ).ToString();
        decimal valueOfDecimal_1 = xmlDecimal.ValueAs<decimal>( decimal.TryParse );
        bool valueOfBool_1 = xmlDecimal.ValueAs<bool>( bool.TryParse );

        var xmlBool = new XElement( "bool" );
        xmlBool.Value = true.ToString();
        decimal valueOfDecimal_2 = xmlBool.ValueAs<decimal>( decimal.TryParse );
        bool valueOfBool_2 = xmlBool.ValueAs<bool>( bool.TryParse );
    }
}

public static class StaticClass {
    public delegate bool TryParseDelegate<T>( string text, out T value );
    public static T ValueAs<T>( this XElement element, TryParseDelegate<T> parseDelegate ) {
        return ValueAs<T>( element, parseDelegate, default( T ) );
    }
    public static T ValueAs<T>( this XElement element, TryParseDelegate<T> parseDelegate, T defaultValue ) {
        if ( null == element ) { return defaultValue; }

        T result;
        bool ok = parseDelegate( element.Value, out result );
        if ( ok ) { return result; }

        return defaultValue;
    }
}

OTHER TIPS

Edit: Given the edited question, this is much simpler.

Again it uses an extension method, but now there's no need to do a conversion in the method.

var myVariable = ParseNDecimal(xml.Element("myElement").ValueOrDefault("0"));

...

public static string ValueOrDefault(this XElement element, 
                                     string defaultValue)
{
    return element != null ? element.Value : defaultValue;
}

If you don't like the method taking a string parameter, you could make it take object and call ToString, then call it like this:

var myVariable = ParseNDecimal(xml.Element("myElement").ValueOrDefault(0m));

However, that feels a little bit wrong to me. It assumes that the parsing will be the reverse of ToString formatting.

Original answer

There's nothing particularly in the language to help you. (I'm not sure that you've got the exact code right - don't you mean something with an XAttribute?) I'd suggest writing a utility method:

var myVariable = xml.Element("myElement").ValueOrDefault(0m);

...

public static decimal ValueOrDefault(this XElement element, 
                                     decimal defaultValue)
{
    return element != null ?(decimal) element.Value : defaultValue;
}

If you adjust the code in the question, I'll do likewise for the code here. I suspect you did mean to use XAttribute, which leads to a problem with generics - I haven't written the above in a generic way, because I believe you will want to call the XAttribute "conversion to decimal" operator. A generic cast won't do that, as it doesn't know what kind of conversion you want at compile time. You can, however, overload the above method for all the result types you're interested in.

You can use the ?? operator to write this a bit more cleanly, but I'm not sure that you should ...

Element() returns null of there is no child element with that name, so that's where you could use ?? to slide in a default element. You need to do this prior to the invocation of the (decimal) cast:

var myVariable 
    = (decimal)(xml.Element("myElement") ?? new XElement("myElement", 0));

Like I said though, while this will work, I'm not sure that you should do this. YMMV.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top