我想知道这个“模式”是否有名称,其中方法签名称为TrySomething,例如int.TryParse
,decimal.TryParse
等
我的同事经常使用这种命名约定 - 而不是返回值或抛出异常,他们将调用方法TryDoSomething
,如果在处理过程中捕获到异常,则会通过out param返回。 / p>
编辑:我理解私有的例子不是TryParse方法的工作原理。这就是张贴这个......我不知道该怎么称呼它。我同意它似乎更像是命名约定而不是模式。感谢您的所有投入。
修改:Interesting ...
考虑可能在常见场景中抛出异常的成员的TryParse模式,以避免与异常相关的性能问题。
要实现TryParse模式,您需要提供两种不同的方法来执行可在常见方案中引发异常的操作。第一个方法X执行操作并在适当时抛出异常。第二种方法TryX不会抛出异常,而是返回一个表示成功或失败的布尔值。使用out(Visual Basic中的ByRef)参数返回成功调用TryX返回的任何数据。 Parse和TryParse方法就是这种模式的例子。
答案 0 :(得分:13)
我可能会称之为Error Hiding Pattern。当您拥有通常会产生异常的代码时,您可以从创建TryX
中受益,而异常则会使用布尔值提前删除。如果你看看框架提供的方法,你会注意到TryX
变体存在,只要它是非平凡的或容易出错的(或者通常它应该在框架中完成)来编写自己的IsValidX
变体{ {1}}方法。
如果你必须捕获异常,那么在方法中包装它是没有意义的。您所做的只是使调试输入问题变得更加困难。用户可能只看到失败方法的副作用,而不是跟踪一个好的堆栈跟踪来追踪输入失败。更糟糕的是,在调试手头的问题时,开发人员可能必须重新创建钝的程序状态才能实现故障模式。
基本上,如果先验您知道操作将因异常而失败,那么提供伴随TryX
操作是合乎逻辑的。这就是所谓的 Tester-Doer 模式。对操作的事后分析不是 Tester-Doer ,而只是简单的异常处理。
答案 1 :(得分:7)
答案 2 :(得分:6)
首先,如果你的描述是准确的,那不是int.TryParse及其兄弟姐妹的工作方式。
我承认,在我看来,这些方法稍有破坏,因为它们没有向调用者传达解析失败的原因,只是失败了。在这方面,我希望看到一个更好的方法来解决这个问题。
事实上,在我看来,更好的方式是我在第三方库中看到的一些我不记得的东西,但基本上他们有各种自定义类型,这些类型具有这样的Parse / TryParse方法,并且他们做了以下事情:
out
参数同样,在我看来,这里的主要问题是它不可扩展。如果我想使用他们的系统和类型,并添加我自己的原因,我不能这样做,但是一些变体很容易处理这个。
在任何情况下,int.TryParse方法都不会在内部抛出任何异常。相反,他们经历了实际解析字符串的动作,如果他们遇到了他们无法应付的事情,他们只会返回虚假,就是这样,没有例外。
异常处理比没有异常的替代方案略贵,这就是为什么一些这样的核心方法针对性能进行了优化的原因。
这就是为什么在我的评论中我调用了你的模式,如果准确,愚蠢,因为你将异常处理与out参数结合起来。一旦你检索到它,你会怎么做?丢它?然后你又回到了第一个方向。
我会认真看看你的模式并尝试改变它。
当然,所有这一切都取决于您对它的描述是否准确的假设。
答案 3 :(得分:4)
我称之为“希望我有Option<T>
”模式(类似于“希望我有Either<T,E>
”模式 - 想象一下E:例外情况。)
TryXYZ(在上面的例子中)使用布尔结果和out
参数模拟Option。 (对于值类型,在这种情况下它可能是Nullable<T>
- 我怀疑它对于int.TryParse
和朋友来说不是这样的,因为Nullable在很晚才到了.NET)。通过out
返回异常更接近于Either。
在C#中,我不建议捕获异常只是为了将它们传递给out
参数(尽管这个“规则”可能与支持有区别的联合和模式匹配的语言不同) - 我尝试1)“正确”地处理它,但是这是定义的,在特定情况下可能可能<{1}} ;或者2)放手让呼叫者也可以尝试。
(正如其他人所指出的,这更像是一种惯例)。
快乐的编码。
答案 4 :(得分:3)
您可以将其称为ExceptionSafeBridge
。它引导您从异常世界到错误代码世界。但我不认为这是正式的。
这种模式是,当你需要在例如C代码和托管代码。
答案 5 :(得分:1)
设计模式通常指的是与语言无关的一般概念,所以不,这不是一种模式。它可能是一个成语,但很可能它只是一个命名惯例,正如Aaron在评论中正确提到的那样。
答案 6 :(得分:1)
是的。它被称为Tester-Doer模式。
答案 7 :(得分:0)
如果在tryparse期间出现问题,即
int val;
if(int.TryParse("2", out val))
{
//do work with val
}
然后你不会通过输出param捕获异常,值0输出为out,false返回为布尔值。
最好的办法是改为使用“是”或“as”。
我不会真的称之为你描述模式的方法......只是编码练习(不是最好的)。
as:
的例子private void SetObj(object obj)
{
int thisInt = obj as int;
if(thisInt != null)
{
//do work
}
else
{
//handle issue
}
}
以上在运行时比try / catch更有效。
如果您使用“is”时(“as”不可用于所有类型),请确保不要通过实现添加冗余,因为WITH只是使用其中一个。