【问题标题】:Whoa, what the TryParse哇,什么 TryParse
【发布时间】:2015-01-07 10:04:31
【问题描述】:

我有一个 Session,其中包含特定的整数值,这些值使用给定的控件进行索引。通常情况下,以下操作就可以了:

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

但是,我确实需要考虑 null。其中,如果string 失败,默认out 将返回null。除了我注意到int.TryParse 不适用于:

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

那么你如何尝试解析,如果失败它会导致 null?

我发现了这个question 并且微软开发者网络规定:

此方法返回时,包含有符号整数值 如果转换成功,则相当于 s 中包含的数字, 如果转换失败,则为零。如果字符串转换失败 参数为 null 或 String.Empty,格式不正确,或 表示小于最小值或大于最大值的数字。这 参数未初始化传递。

明确指出,如果int.TryParse 失败,整数将保持零值。在我的使用实例中,零可能是有效值。所以我需要null,有什么想法吗?

【问题讨论】:

  • 为什么常规演员不能工作? (int?)(Session["Key"])
  • @AlexeiLevenkov 我可能会这样做:Session["Key"] as int? 如果失败,它将返回 nullable。
  • 我有点困惑-我假设您将 nullable 放入会话状态-因此将有有效的int? 值或缺少键-两者都应该与 cast/as 一起成功。我没有看到“失败”的情况......
  • @AlexeiLevenkov 你是对的,但其他开发人员可能会做“坏数据”。虽然他们不应该。
  • @AlexeiLevenkov 常规转换​​的另一个潜在问题是,如果失败,它会在 IIS 中引发您不希望用户看到的异常。

标签: c# asp.net asp.net-mvc webforms


【解决方案1】:

当然;利用int.TryParse的返回值(如果转换成功则返回):

int? retValue = null;
int parsedValue = 0;

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

return retValue;

我承认有点冗长,但你可以将它包装在一个函数中。

【讨论】:

    【解决方案2】:
    int tmp;
    int? value = int.TryParse(Session["Key"].ToString(), out tmp) ? (int?)tmp : null;
    

    【讨论】:

    • 当键不存在/具有null 值时,此代码显然会抛出 NullReferenceException(与 OP 想要的行为完全相同,但不是其他人可能需要的行为。当心)。
    • @AlexeiLevenkov 毫无疑问,但我想这超出了这个问题的范围。
    【解决方案3】:

    问题在于“null”这个词。这是什么意思? null 可能意味着该值无法确定,引发了异常,仅仅是该值为 null 或其他一些上下文含义。您的问题就是一个很好的例子,因为您自己在任意声明,在您看来,null 表示字符串解析失败。

    Microsoft 的 TryParse 范例很棒,但用途有限。考虑以下场景:

    • 字符串 == "89"
    • 字符串 == 空
    • string == "Hello World"
    • 字符串 == ""
    • 字符串 == "2147483650"

    然而,您唯一的选择是将 Integer 或 Null 分配给您的输出,并返回 true 或 false。

    假设它有效,您将如何处理这些信息?像这样?

    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.
    }
    

    考虑这个 NullableInt TryParse 示例:

    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;
    }
    

    一种解决方案是使用枚举 TryParse 而不是布尔 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;
    }
    

    另一个问题是out 变量的存在。您的第三个选择是使用描述性单子,如下所示:

    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);
    }
    

    您可以将 Monad 用作单枚举值,或者像这样:

    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
    

    使用 Monads 和可能的枚举 TryParses,您现在可以从描述性返回中获得所需的所有信息,并且没有人需要猜测 null 可能意味着什么。

    【讨论】:

    • 很好的答案!我只是在考虑用简单的 Maybe monad 替换 TryParse 模式。我认为'out'参数增加了不必要的复杂性。对于更简单的场景,我什至使用现在有更好支持的命名元组。 (success, result) = FuncName(..);public (bool success, Subject result) FuncName (args..) {}
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-20
    • 1970-01-01
    • 1970-01-01
    • 2016-08-12
    • 1970-01-01
    • 1970-01-01
    • 2011-08-18
    相关资源
    最近更新 更多