为什么 TryParse 是这样的?
Why is TryParse the way round that it is?
我一直在努力寻找一种使用 TryParse
的自然方式,因为我一直期望它能以相反的方式工作(即 return 解析值并发出输入是否被解析的布尔值)。
例如,如果我们采用 Parse
的基本实现,则 return 值是已解析的输入:
int parsedValue = int.Parse(input);
在它获得无法解析的值之前,它工作正常,此时它完全合理地抛出异常。对我来说,选择是将解析包装在类似 try-catch 块的东西中以处理异常和设置默认值的条件,或者只是使用 TryParse
让 C# 为我做所有这些。除了那不是 TryParse
的工作方式。上面的例子现在看起来像这样:
bool parseSucceeded = int.TryParse(input, out int parsedValue);
为了让它以与 Parse
相同的方式分配,我将其包装在一个三元条件中,其中 parsedValue
和一个默认值(在本例中为 0)作为 true
和 false
结果分别为:
int parsedValue = int.TryParse(input, out parsedValue) ? parsedValue : 0;
但如果我只是像这样解决它的默认行为,我仍然觉得我错过了 TryParse
的要点。我已经阅读了 Tim Schmelter's excellent answer in which he shows its internal workings, from which I can suppose that it returns the boolean because it's easier internally than passing it out at all the various places that it currently returns. But I'm not sure about this, and I'm not satisfied that I understand its intent correctly. I also tried reading the documentation,但这些评论并没有消除我的困惑(我认为他们甚至没有足够清楚地说明它与 Parse
的区别,比如 return类型)。
我理解正确吗,还是我遗漏了什么?
因为从逻辑上讲,您希望在尝试使用 out
值之前检查 TryParse
是否成功。
所以这样更简洁:
if (int.TryParse(input, out int parsedValue)}
{
// Do something with parsedValue
}
比这个:
int parsedValue = int.TryParse(input, out bool succeded);
if (succeeded)
{
// Do something with parsedValue
}
当然,它可以实现为
int TryParse(string input, out bool succeeded)
{
}
但是正如评论中提到的,该函数的常见用例是:
string input;
int parsedValue;
if(int.TryParse(input, out parsedValue))
{
// use parsedValue here
}
根据您提出的签名,该代码现在为:
string input;
bool succeeded;
int parsedValue = int.TryParse(input, out succeeded)
if(succeeded)
{
// use parsedValue here
}
所以有更多的代码没有任何功能优势。此外,对于你的三元运算符,如果解析失败,你只需将值设置为零,这是不必要的,因为它的默认值为 0。你可以这样做:
int parsedValue;
int.TryParse(input, out parsedValue);
如果解析失败,parsedValue
的值为0; (我还质疑 if/how 你区分 实际 结果 0 和失败的解析,但我相信你有理由)。
所以没有技术签名的原因;这是适合最常见用例的设计决策。
当然,现在有了 C# 7 中的元组,您可以拥有:
(int parsedValue, bool succeeded) = int.TryParse(input);
但同样没有什么功能上的好处,并且会阻止您在 if
语句中内联 TryParse
。
我认为,您的困惑很大一部分源于方法名称的命名不正确:
int parsedValue = int.Parse("42");
这很有道理,给我一个字符串的整数表示。
int parsedValue = int.TryParse(input);
这作为概念的扩展是有意义的:输入可能是“42”或 'Oswald',但如果它是一个数字,我想要那个数字。
2020 年,我认为更好的名字是 CanParse(string input, out int result)
。
- 它更符合风格指南和命名约定,其中返回的 bool 应使用 Is、Has 或 Can 命名。
它更符合我们 99% 的时间使用 TryParse 的方式:
if (int.CanParse(input, out int result))
{
return result * 10;
}
但我觉得当前名称有意义的地方是我认为它试图解决的问题:摆脱以下样板代码:
int result;
bool hasValidNumber = false;
try
{
result = int.Parse(input);
hasValidNumber = true;
}
catch
{
// swallow this exception
}
if (hasValidNumber)
{
// do things with result
}
else
{
// use a default or other logic
}
我一直在努力寻找一种使用 TryParse
的自然方式,因为我一直期望它能以相反的方式工作(即 return 解析值并发出输入是否被解析的布尔值)。
例如,如果我们采用 Parse
的基本实现,则 return 值是已解析的输入:
int parsedValue = int.Parse(input);
在它获得无法解析的值之前,它工作正常,此时它完全合理地抛出异常。对我来说,选择是将解析包装在类似 try-catch 块的东西中以处理异常和设置默认值的条件,或者只是使用 TryParse
让 C# 为我做所有这些。除了那不是 TryParse
的工作方式。上面的例子现在看起来像这样:
bool parseSucceeded = int.TryParse(input, out int parsedValue);
为了让它以与 Parse
相同的方式分配,我将其包装在一个三元条件中,其中 parsedValue
和一个默认值(在本例中为 0)作为 true
和 false
结果分别为:
int parsedValue = int.TryParse(input, out parsedValue) ? parsedValue : 0;
但如果我只是像这样解决它的默认行为,我仍然觉得我错过了 TryParse
的要点。我已经阅读了 Tim Schmelter's excellent answer in which he shows its internal workings, from which I can suppose that it returns the boolean because it's easier internally than passing it out at all the various places that it currently returns. But I'm not sure about this, and I'm not satisfied that I understand its intent correctly. I also tried reading the documentation,但这些评论并没有消除我的困惑(我认为他们甚至没有足够清楚地说明它与 Parse
的区别,比如 return类型)。
我理解正确吗,还是我遗漏了什么?
因为从逻辑上讲,您希望在尝试使用 out
值之前检查 TryParse
是否成功。
所以这样更简洁:
if (int.TryParse(input, out int parsedValue)}
{
// Do something with parsedValue
}
比这个:
int parsedValue = int.TryParse(input, out bool succeded);
if (succeeded)
{
// Do something with parsedValue
}
当然,它可以实现为
int TryParse(string input, out bool succeeded)
{
}
但是正如评论中提到的,该函数的常见用例是:
string input;
int parsedValue;
if(int.TryParse(input, out parsedValue))
{
// use parsedValue here
}
根据您提出的签名,该代码现在为:
string input;
bool succeeded;
int parsedValue = int.TryParse(input, out succeeded)
if(succeeded)
{
// use parsedValue here
}
所以有更多的代码没有任何功能优势。此外,对于你的三元运算符,如果解析失败,你只需将值设置为零,这是不必要的,因为它的默认值为 0。你可以这样做:
int parsedValue;
int.TryParse(input, out parsedValue);
如果解析失败,parsedValue
的值为0; (我还质疑 if/how 你区分 实际 结果 0 和失败的解析,但我相信你有理由)。
所以没有技术签名的原因;这是适合最常见用例的设计决策。
当然,现在有了 C# 7 中的元组,您可以拥有:
(int parsedValue, bool succeeded) = int.TryParse(input);
但同样没有什么功能上的好处,并且会阻止您在 if
语句中内联 TryParse
。
我认为,您的困惑很大一部分源于方法名称的命名不正确:
int parsedValue = int.Parse("42");
这很有道理,给我一个字符串的整数表示。
int parsedValue = int.TryParse(input);
这作为概念的扩展是有意义的:输入可能是“42”或 'Oswald',但如果它是一个数字,我想要那个数字。
2020 年,我认为更好的名字是 CanParse(string input, out int result)
。
- 它更符合风格指南和命名约定,其中返回的 bool 应使用 Is、Has 或 Can 命名。
它更符合我们 99% 的时间使用 TryParse 的方式:
if (int.CanParse(input, out int result)) { return result * 10; }
但我觉得当前名称有意义的地方是我认为它试图解决的问题:摆脱以下样板代码:
int result;
bool hasValidNumber = false;
try
{
result = int.Parse(input);
hasValidNumber = true;
}
catch
{
// swallow this exception
}
if (hasValidNumber)
{
// do things with result
}
else
{
// use a default or other logic
}