为什么解析助手不易使用?

时间:2013-02-05 12:40:50

标签: c# parsing language-design nullable deprecated

鉴于.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;
}

2 个答案:

答案 0 :(得分:2)

此签名:

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

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

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

public static int? TryParse(string s)

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

string s = ...
int value = int.TryParse(s) ?? 0;

答案 1 :(得分:2)

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

有些注意事项可能是:

  1. 更改方法将构成更改 现有的代码库,只有极少的(如果有的话)有意义的增益。一些 可能会认为这对以下原因有害。
  2. Nullable types 框包装包装基础值导致(次要)性能损失 即使你希望你的解析成功并且不想要一个 无论如何都是可空的。
  3. 如果知道您的输入假设有效,那么Parse 方法抛出输入的例外情况的异常 是无效的。这通常更具性能,因为我们没有额外的 错误处理代码,当我们不需要它时,并期望从a 设计观点。如果您打算处理无效案件, 这就是TryParse的用途。
  4. int Parse(string, int? defaultValue)int Parse(string)之间的混淆,主要是关于错误处理。注意 我删除了第一种方法的可选部分,否则就会删除 两种方法都没有意义(你永远无法调用 没有明确传入null)的方法。在这一点上,它 因为一个超载会引发异常,所以会有点混乱 失败,而另一个没有。有一些例外 对此,如 Type.GetType 但它们通常很少见,在这种情况下,它们会使用显式命名的参数,表明它不会抛出异常。
  5. TryParse设计的另一个好处是它很漂亮 通过其API显式处理传递/失败结果。宁 而不是指示失败的幻数/结果(null),它返回 一个单独的 true / false值。现在,一些机制就是这样做的 (String.IndexOf例如返回-1)所以它是有争议的 这是好事还是坏事。根据你的实践, 使用返回true/false值可能更容易,或使用 魔术null结果可能是。但他们认为我猜不会浑浊 有两种方法的水完全相同,但有 略有不同的签名/返回值。
  6. 另一个考虑因素是常见的可空值类型。是 你真的在很多地方使用Int32?吗?或者只是为了 错误/输入处理?根据我的经验,可以为空的值主要是 用于数据库I / O(即使这样,也不常用)。唯一的 其他时间可能是来自不信任来源的输入 仅用于初始接口;所有底层代码仍然存在 键入不可为空的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(),如果您知道它是非空的,那么实际上 faster/better way to access the wrapped value,但很少(在 至少来自我在互联网上看到的内容)是在Value上使用的 访问。如果BCL像您一样添加/更改了Parse方法 建议,我认为很多的人会不必要地打击 Value访问者。

    对于使用可空值的案例,我无法对具体发表评论 在整个应用程序设计和/或其层中, 但根据我的经验,他们很少使用或应该很少使用(对我而言,它几乎在“串型”数据的水平上是一种代码味道)

  7. 最终,我相信部分之所以添加扩展方法(除了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并不是一个大问题。