这种反模式/代码气味有名字吗?
首先,我说我不主张这种做法,但最近我看到了,我想知道是否有一个名字可以用来指认有罪的政党。所以去。
现在我们有了一个方法,并且想要返回一个值。我们还想返回一个错误代码。当然,异常是更好的选择,但是无论出于何种原因,我们都希望使用错误代码。记住,我在这里扮演恶魔的拥护者。因此,我们将创建一个通用类,如下所示:
class FunctionResult<T> { public T payload; public int result; }
然后像这样声明你的函数:
FunctionResult<string> MyFunction() { FunctionResult<string> result; //... return result; }
此模式的一种变体是对错误代码使用枚举而不是字符串。现在,回到我的问题:对此有一个名称吗,如果是的话,它是什么?
解决方案
回答
"无法确定这是否是错误"模式如何呢?好像我们确实有异常,但想返回部分结果,则将结果包装在异常中。
回答
我不确定这是否是反模式。出于性能原因,我经常看到使用此方法而不是使用异常,或者可能是为了使该方法失败的事实更加明确。在我看来,这似乎是个人喜好而不是反模式。
回答
用异常替换错误代码
回答
好吧,这不是反模式。 C ++标准库利用了此功能,.NET甚至在.NET框架中提供了一个特殊的FunctionResult
类。它被称为"可空"。是的,这不仅限于函数结果,还可以用于此类情况,在这里实际上非常有用。如果.NET 1.0已经具有" Nullable"类,则肯定会将其用于" NumberType.TryParse"方法,而不是" out"参数。
回答
实际上,这种方法比我所见过的其他方法要好得多。例如,C语言中的某些函数在遇到错误时会返回并似乎成功。告诉他们失败的唯一方法是调用一个函数,该函数将获得最新的错误。
我花了数小时试图在MacBook上调试信号灯代码,然后才最终发现sem_init在OSX上不起作用!它编译时没有错误,并且在运行时没有引起任何错误,但是该信号灯不起作用,我不知道为什么。我很遗憾将使用POSIX信号的应用程序移植到OSX并必须处理已经调试的资源争用问题的人们。
回答
我通常将有效负载作为(非const)引用传递,并将错误代码作为返回值传递。
我是游戏开发人员,我们排除了例外情况
回答
我同意这不是专门的反模式。根据使用情况,可能会有异味。有一些原因导致人们实际上不希望使用异常(例如,对于初学者来说,返回的错误不是" exception")。
在某些情况下,我们希望服务为其结果返回一个通用模型,包括错误和良好值。这可能被低级服务交互所包装,该服务交互将结果转换为异常或者其他错误结构,但是在服务级别,它使服务可以返回结果和状态代码,而不必定义可能必须跨远程边界进行翻译。
该代码也不一定是错误:考虑一个HTTP响应,该响应由许多不同的数据(包括状态码)和响应主体组成。
回答
如果我们不想使用异常,则最干净的方法是让函数返回错误/成功代码,并采用填充了结果的引用或者指针参数。
我不会称其为反模式。这是一种行之有效的可行方法,通常比使用异常更可取。
回答
如果我们希望方法偶尔会失败,但又不要认为这种例外,我更喜欢.NET Framework中使用的这种模式:
bool TryMyFunction(out FunctionResult result){ //... result = new FunctionResult(); }
回答
Konrad是正确的,Cuses始终都具有双返回值。但是我有点像C#中的TryParse,Dictionary.TryGetValue等方法。
int value; if (int.TryParse("123", out value)) { // use value }
代替
int? value = int.TryParse("123"); if (value != null) { // use value }
...主要是因为Nullable模式无法缩放为非Value返回类型(即类实例)。这不适用于Dictionary.TryGetValue()。而且TryGetValue不仅比KeyNotFoundException(在调试器中始终没有"第一次机会异常",而且效率更高)更好,而且比Java的get()返回null(如果期望null值的做法)更好,并且比必须这样做更有效。首先调用ContainsKey()。
但这仍然有点麻烦-因为它看起来像C#,所以应该使用out参数。实例化类可能会损失所有效率提高。
(除了" string"类型为小写字母外,它可以是Java。在Java中,我们当然必须使用一个类来模拟双返回值。)
回答
我同意那些说这不是反模式的人的观点。在某些情况下,这是一种完全有效的模式。在特殊情况下例外,在预期情况下应使用返回值(如示例)。某些域期望类产生有效和无效的结果,并且都不应该将它们建模为异常。
例如,给定X数量的汽油,一辆汽车可以从A到B行驶吗?如果有,还剩下多少汽油?对于我们提供的数据结构,这种问题是理想的。预期无法进行从A到B的旅行,因此不应使用异常。
回答
为了辩护反模式,此代码可通过以下几种方式使用:
- 对象x = MyFunction()。payload; (忽略返回结果-非常糟糕)
- int代码= MyFunction()。result; (扔掉有效载荷-如果这是预期用途,可能会没事的。)
- FunctionResult x = MyFunction(); // ...(一堆额外的FunctionResult对象和额外的代码来检查它们)
如果我们需要使用返回码,那很好。但是,然后使用返回码。不要尝试在其中打包额外的有效负载。这就是ref和out参数(C#)的目的。可空类型可能是一个例外,但这仅是因为在语言中还增加了额外的糖来支持它。
如果我们仍然不同意此评估,请对这个答案(不是整个问题)进行投票。如果我们确实认为这是一种反模式,请对其进行投票。我们将使用此答案来查看社区的想法。
回答
关于气味和反模式的辩论让我想起了"幸存者"电视节目,那里有各种各样的编程结构试图在岛上互相投票。我宁愿看到" construct X具有某种优缺点",而不是不断发展的关于应该做什么和不应该做什么的法令列表。