这种反模式/代码气味有名字吗?

时间:2020-03-05 18:56:03  来源:igfitidea点击:

首先,我说我不主张这种做法,但最近我看到了,我想知道是否有一个名字可以用来指认有罪的政党。所以去。

现在我们有了一个方法,并且想要返回一个值。我们还想返回一个错误代码。当然,异常是更好的选择,但是无论出于何种原因,我们都希望使用错误代码。记住,我在这里扮演恶魔的拥护者。因此,我们将创建一个通用类,如下所示:

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具有某种优缺点",而不是不断发展的关于应该做什么和不应该做什么的法令列表。