2

鉴于 .NET 团队已经声明(我会找到一个来源......)他们对原始类型的解析方法(例如Int32.TryParse(String s, out Int32 result))的设计感到遗憾,为什么没有使用更明显和对客户端友好的变体来更新这些方法?

框架版本:

Int32? numValue;
Int32 placeHolder;
if (! Int32.TryParse("not a number", out placeHolder))
    numValue = 10;

改良版:

var numValue = Int32.Parse("not a number", 10);

改进的解析方法的签名是:

public static Int32? Parse(String s, Int32? defaultValue = null);

它可能有一个幼稚的实现:

public static Int32? Parse(String s, Int32? defaultValue = null) {
    Int32 temp;
    return ! Int32.TryParse(s, out temp)
        ? defaultValue
        : temp;
}
4

2 回答 2

2

这个签名:

public static Int32? Parse(String s, Int32? defaultValue = null);

会与现有的Parse(string s)重载冲突,因为如果未指定可选参数,则无法区分它们。现有方法可能永远不会更改或删除,因为它会破坏与现有代码的兼容性。

但是,可以创建TryParse不带out int value参数的重载:

public static int? TryParse(string s)

请注意,您不需要为默认值添加参数:您可以改用 null 合并运算符。

string s = ...
int value = int.TryParse(s) ?? 0;
于 2013-02-05T13:07:43.323 回答
2

我不确定是否会有明确的答案,除非 BCL 团队的某个人有故事要讲。

一些考虑可能是:

  1. 更改方法将对现有代码库构成重大的重大更改,而收益很少(如果有的话,值得商榷)。有些人可能会争辩说,由于以下原因,这将是有害的。
  2. 可空类型包装的基础值封装起来,即使您希望解析成功并且无论如何都不想要可空类型,也会导致(次要)性能下降。
  3. 如果您知道您的输入应该是有效的,那么该Parse 方法会在输入无效的例外情况下抛出异常。这通常更高效,因为我们没有额外的错误处理代码,当我们不需要它时,并且从设计的角度来看是预期的。如果您打算处理无效案件,那就是这样TryParse做的。
  4. int Parse(string, int? defaultValue)和之间的混淆int Parse(string),主要是关于它们的错误处理。请注意,我已经删除了第一个方法的可选部分,否则同时拥有这两种方法是没有意义的(如果没有显式传递,您将永远无法调用您的方法null)。在这一点上,它会有点令人困惑,因为一个重载会在失败时引发异常,而另一个则不会。对此有一些例外,例如 Type.GetType 但它们通常很少见,在这种情况下,它们使用显式命名的参数来指示它将不会抛出异常。
  5. 设计的另一个好处TryParse是,它通过 API 非常明确地处理通过/失败结果。它不是一个null指示失败的幻数/结果 (),而是返回一个单独的真/假值。现在,一些机制会这样做(String.IndexOf例如返回-1),所以这是好事还是坏事还有待商榷。根据您的实践,使用返回true/false值可能会更容易,或者使用神奇的null结果可能会更容易。但是他们决定我猜不要用两种方法做完全相同的事情,但签名/返回值略有不同。
  6. 另一个考虑因素是可空值类型的常见程度。你真的Int32?在很多地方使用吗?还是仅用于错误/输入处理?以我的经验,可为空的值主要 用于数据库 I/O(即便如此,也不经常使用)。唯一的其他时间可能是来自不可信来源的输入,这些输入仅用于初始接口;所有底层代码仍将针对 non-nullable 键入Int32。在这种情况下,您有两种方法,原始方法:

    int input;
    if (TryParse(someString, out input))
        DoSomethingValid(input); //valid! Do something
    else
        ErrorMessage()//not valid, error!
    

    或者你的建议:

    int? input = Parse(someString)
    if (input != null)
        DoSomethingValid(input.GetValueOrDefault())//valid! Do something
    else
        ErrorMessage()//not valid, error!
    

    请注意两者的相似之处。如果对这种情况有任何帮助,您的建议确实提供的很少。还要注意 的用法,如果您知道它是非空的 GetValueOrDefault(),这实际上是访问包装值的更快/更好的方法,但很少(至少从我在互联网上看到的)它在Value 访问器上使用。如果 BCL 按照您的建议添加/更改Parse方法,我认为很多人会不必要地点击Value访问器。

    我不能特别评论在整个应用程序设计和/或其层中显着使用可为空值的情况,但根据我的经验,它们很少使用或应该很少使用(对我来说,这几乎是“字符串”级别的代码气味类型的”数据)

最终,我相信添加扩展方法(除了 Linq)的部分原因是允许用户根据需要滚动他们自己的 API。在您的情况下,您可以轻松添加扩展方法来获得所需的语法:

public static Int32? Parse(this String s, Int32? defaultValue = null)
{
    Int32 temp;
    return !Int32.TryParse(s, out temp)
        ? defaultValue
        : temp;
}

string validString = "1";
int? parsed = validString.Parse(); //1
int? failParsed = "asdf".Parse(9); //9

团队通常倾向于保持现状,并且添加必须提供足够显着的好处才能添加到系统中,并且团队还考虑 API 中已经存在哪些变通方法。我建议考虑到扩展方法选项,考虑到 API 的重大破坏性,更改 API 并不是什么大问题。

于 2013-02-05T13:19:56.483 回答