Whoa what TryParse

I have a session that contains certain integer values ​​that are indexed with given controls. Typically, the following will work very well:

int value;
int.TryParse(Session["Key"].ToString(), out value);

      

However, I need to account for null. If, if string

failed, the default will return a null

. Also, I noticed that int.TryParse

doesn't work with:

int? value = null;
int.TryParse(Session["Key"].ToString(), out value);

      

So how can you try this parsing if it fails, it will result in an error?

I found this question and the Microsoft Developer Network dictates:

When this method returns, contains a signed integer value equivalent to the number contained in s if the conversion succeeded, or zero if the conversion failed. The conversion fails if the parameter string is null or String.Empty, is not in the correct format, or is less than Min Value or greater than Max Value. This parameter is passed uninitialized.

Which explicitly indicates, if int.TryParse

not working, the integer will contain the value 0. In my use case, zero might be a valid value. So what do I need null

, any thoughts?

+3


source to share


3 answers


Sure; use the return value int.TryParse

(which is returned if the conversion is successful or not):

int? retValue = null;
int parsedValue = 0;

if (int.TryParse(Session["Key"].ToString(), out parsedValue))
    retValue = parsedValue;
else
    retValue = null;

return retValue;

      



A bit verbose, I agree, but you can wrap it in a function.

+9


source


int tmp;
int? value = int.TryParse(Session["Key"].ToString(), out tmp) ? (int?)tmp : null;

      



+6


source


The problem is with the word "null". What does it mean? null

could mean that the value is undefined, an exception was thrown simply that the value is null or some other contextual value. Your question is a perfect example because you yourself are arbitrarily claiming what you think null

means the string parsing failed.

The Microsoft TryParse paradox is great, but for limited use. Consider these scenarios:

  • string == "89"
  • string == null
  • string == "Hello World"
  • string == ""
  • string == "2147483650"

However, your only options are to assign Integer or Null to your output and return true or false.

Assuming it worked, what are you going to do with this information? Something like that?

int? value = null;
if (int.TryParse(Session["Key"].ToString(), out value)) {
    if (value == null)
        // Handle "Appropriate" null
    else
        // Handle appropriate numeric value
}
else {
    // Note: value == null here, and TryParse failed
    // Handle null...
    // What if the reason it failed was because the number was too big?
    // What if the string was Empty and you wanted to do something special?
    // What if the string was actually junk?  Like "(423)322-9876" ?
    // Long-Story Short: You don't know what to do here without more info.
}

      

Consider a NullableInt TryParse example:

public bool TryParseNullableInt(string input, out int? output)
{
    int tempOutput;
    output = null;
    if (input == null) return true;
    if (input == string.Empty) return true; // Would you rather this be 0?

    if (!int.TryParse(input, out tempOutput))
        return false; // What if string was "2147483650"... or "Twenty Three"?
    output = tempOutput;

    return true;
}

      

One solution is to use the TryParse enumeration instead of the boolean TryParse:

public ParseStatus TryParseNullableInt(string input, out int? output)
{
    int tempInteger;
    output = null;
    if (input == null) return ParseStatus.Success;
    if (input == string.Empty) { output = 0; return ParseStatus.Derived; }

    if (!int.TryParse(input, out tempInteger)) {
        if (ParseWords(input, out tempInteger)) { // "Twenty Three" = 23
            output = tempInteger;
            return ParseStatus.Derived;
        }
        long tempLong;
        if (long.TryParse(input, out tempLong))
            return ParseStatus.OutOfRange;
        return ParseStatus.NotParsable;
    }
    output = tempInteger;

    return ParseStatus.Success;
}

      

Another problem is the existence of the variable out

. Your third option is to use a descriptive monad, something like this:

public Maybe<int?> TryParseNullableInt(string input)
{
    if (input == null) return Maybe.Success(null);
    if (input == string.Empty) { return Maybe.Derived(0); }

    int tempInteger;
    if (!int.TryParse(input, out tempInteger)) {
        if (ParseWords(input, out tempInteger)) { // "Twenty Three" = 23
            return Maybe.Derived(tempInteger);
        }
        long tempLong;
        if (long.TryParse(input, out tempLong))
            return Maybe.OutOfRange();
        return Maybe.NotParsable();
    }

    return Maybe.Success(tempInteger);
}

      

You can use Monads as Single-Enumerable Values ​​or like this:

Maybe<int?> result = TryParseNullableInt("Hello");
if (result.HasValue) {
    if (result.Status == ParseStatus.Success)
        // Do something you want...
    else if (result.Status == ParseStatus.Derived)
        // Do something else... more carefully maybe?
}
else if (result.Status == ParseStatus.OutOfRange)
    MessageUser("That number is too big or too small");
else if (result.Status == ParseStatus.NotParsable)
    // Do something

      

With Monads and possibly TryParses enums, you now have all the information you need from the descriptive return, and no one has to guess what that might mean null

.

+1


source







All Articles