何时使用“Try”方法而不是“null”结果?

3
在.NET Framework(泛型出现时),Try[method]模式出现了,以帮助处理操作需要指示未能成功完成而不抛出异常的情况。
在一些认为失败是正常的情况下(例如解析),这显然是一个值得遵循的模式。
然而,如果一个方法可以返回null来表示它未能成功获取值(例如在Find方法中的情况),那么这是否比使用明确指示成功或失败的返回值的TryFind方法更正确?.NET Framework对此模式有任何先例吗?
7个回答

2
< p > null 返回类型的问题在于需要检查它 - 这可能不明显,很容易被忘记。

< p > 使用 Try* 类型方法可以使流程更加清晰。

< p > 尽管如此,null 对象模式 正是由于返回 null 的问题而存在 - 它允许您使用一个 "null" 对象作为您的类型,这是一个表示中性值的有效对象。


很久没看到有关空对象模式的参考了。 - Paul Turner

2
  1. 普通值类型不支持null。虽然有可空值类型,但泛型不支持这样的构造:如果T是值类型,则返回T?,如果T是引用类型,则返回T
  2. 对于支持null的类型,null是一个有效值。用户可能想区分缺失的条目和null条目。

另一方面,可以定义一个Option<T>结构来返回。这种类型在其他地方也很有用(例如可选参数)。


有趣的是,非泛型的HashTable类在其索引器中返回null,当元素不存在时:

与指定键相关联的值。如果未找到指定的键,则尝试获取它将返回null,并尝试设置它将创建一个使用指定键的新元素。

要区分因未找到指定键而返回的null和因指定键的值为null而返回的null,请使用Contains方法或ContainsKey方法确定列表中是否存在该键。


这样说:“null是一个有效的值。用户可能想区分缺失的条目和空条目。” - Ben Voigt

2
我相信TryX模式早于.NET 2.0中添加的Nullable类型。Nullable解决了值类型和默认类型值是否有效/无效之间潜在差异的问题。但即使有这些增强功能,我仍然认为TryX模式仍然具有价值。
TryX模式的两个主要优点是:
- 没有返回值的歧义。 - 免受异常的影响。
Nullable类型消除了歧义,但不提供异常安全性。
我不认为有一个明确的先例,但如果您的方法需要保证这些内容,则应使用TryX模式。

1

相当多的TryParse方法返回值而不是对象,这意味着它们不能返回null。当然,通过引入Nullable,它们可以被编写为返回null,但null被定义为“没有信息”。在异常/错误的情况下,这不符合语义。成功时返回true,失败时返回false,清晰地表示了这些信息。 正如下面的评论所述,这也符合.NET框架中TryParse方法的设计。它们与Nullable同时引入。 您还可以避免某人在未检查null的情况下使用返回值,这比忘记检查TrySomething方法的结果更容易出错。


“TryParse” 方法是在 Framework 2.0 中引入的,这也是引入 “Nullable<T>” 的版本。虽然这个概念早已存在,但设计师们决定采取不同的方法。 - Paul Turner
@ProgrammingHero 这就是我的观点 :) 现在我已经试着更清晰地表达了,感谢您的评论(TryParse 方法比 .NET 中引入的方法更早)。 - Rune FS

0

异常不应该用于流程控制或方法的结果。当然,总有例外。这就是使用TryParse而不是Try的原因之一。


1
我没有看到 OP 建议使用异常作为流程控制的方法(实际上相反)。 - Rune FS

0
一个原因是当你返回一个不能为null的结构体时,例如double.TryParse()

但是这可能被重写为返回Nullable<double>,但我认为不应该这样做。 - Rune FS
首先,这种方法是在引入Nullable<T>之前实现的。此外,在BLC中常见的模式是当解析失败时抛出异常。TryParse方法返回布尔值,并使用out参数在解析成功时返回实际值。 - Jakub Konecki
是的,double.TryParse(而不是int.TryParse)在Nullable <T>之前被引入,但根据我所读到的OP,他并不是在追溯过去,而是在询问与他当前工作相关的问题,因此对于新开发来说并不起作用的追溯性论点在我的看法中并没有太大帮助。 - Rune FS

0
对于返回类类型的方法,我更喜欢使用返回 null 的 TryGetFnord() 方法来代替返回 bool 并将其结果存储在 ref 参数中的方法。其中一个原因是前者可以包含在协变接口中,而后者则不行。但我建议在名称中保留 "Try",以表明该方法可能会失败。
另一种考虑的方法是:使用 dataType TryGetFnord(ref TryGetFnordResult result) 这样的形式,其中 TryGetFnordResult 可以是值类型或不可变类类型,用于指示操作是否成功。这将保留协变相关的优势,同时允许返回比仅仅是通过/不通过更有用的信息。如果操作失败,则应该返回其类型的默认值,但调用者应该使用 result 参数检查失败情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接