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

发布于 2024-07-06 09:08:05 字数 532 浏览 9 评论 0原文

首先我要说的是,我并不提倡这种方法,但我最近看到了它,我想知道是否有一个名称可以用来指出有罪的一方。 所以就这样吧。

现在您有了一个方法,并且想要返回一个值。 您想要返回错误代码。 当然,异常是更好的选择,但无论出于何种原因,您都需要错误代码。 请记住,我在这里扮演魔鬼代言人的角色。 因此,您创建一个泛型类,如下所示:

class FunctionResult<T>
{
    public T payload;
    public int result;
}

然后像这样声明您的函数:

FunctionResult<string> MyFunction()
{
    FunctionResult<string> result;
    //...

    return result;
}

此模式的一种变体是使用枚举作为错误代码而不是字符串。 现在,回到我的问题:这个有名字吗?如果有的话,它是什么?

Let me start by saying that I do not advocate this approach, but I saw it recently and I was wondering if there was a name for it I could use to point the guilty party to. So here goes.

Now you have a method, and you want to return a value. You also want to return an error code. Of course, exceptions are a much better choice, but for whatever reason you want an error code instead. Remember, I'm playing devil's advocate here. So you create a generic class, like this:

class FunctionResult<T>
{
    public T payload;
    public int result;
}

And then declare your functions like this:

FunctionResult<string> MyFunction()
{
    FunctionResult<string> result;
    //...

    return result;
}

One variation on this pattern is to use an enum for the error code instead of a string. Now, back to my question: is there a name for this, and if so what is it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

夏末的微笑 2024-07-13 09:08:06

为了捍卫反模式指定,此代码适合以多种方式使用:

  1. Object x = MyFunction().payload; (忽略返回结果 - 非常糟糕)
  2. int code = MyFunction().result; (扔掉有效负载 - 如果这是预期用途,可能没问题。)
  3. FunctionResult x = MyFunction(); //... (一堆额外的 FunctionResult 对象和额外的代码来检查它们)

如果您需要使用返回代码,那很好。 但随后使用返回码。 不要尝试在其中打包额外的有效负载。 这就是 refout 参数 (C#) 的用途。 可空类型可能是一个例外,但这只是因为语言中添加了额外的糖分来支持它。

如果您仍然不同意此评估,请否决此答案(不是整个问题)。 如果您确实认为这是一种反模式,请对其进行投票。 我们将使用这个答案来了解社区的想法。

In defense of the anti-pattern designation, this code lends itself to being used in a few ways:

  1. Object x = MyFunction().payload; (ignoring the return result - very bad)
  2. int code = MyFunction().result; (throwing away the payload - may be okay if that's the intended use.)
  3. FunctionResult x = MyFunction(); //... (a bunch of extra FunctionResult objects and extra code to check them all over the place)

If you need to use return codes, that's fine. But then use return codes. Don't try to pack an extra payload in with it. That's what ref and out parameters (C#) are for. Nullable types might be an exception, but only because there's extra sugar baked in the language to support it.

If you still disagree with this assessment, DOWNVOTE this answer (not the whole question). If you do think it's an anti-pattern, then UPVOTE it. We'll use this answer to see what the community thinks.

忆依然 2024-07-13 09:08:05

我同意这并不是一种特定的反模式。 根据使用情况,可能会有气味。 人们实际上不想使用异常是有原因的(例如,对于初学者来说,返回的错误不是“异常”)。

在某些情况下,您希望服务返回其结果的通用模型,包括错误和正确值。 这可能由低级服务交互包装,将结果转换为异常或其他错误结构,但在服务级别,它允许服务返回结果和状态代码,而无需定义某些可能会导致异常的异常结构。必须跨越远程边界进行翻译。

此代码也不一定是错误:考虑一个 HTTP 响应,它由许多不同的数据组成,包括状态代码以及响应正文。

I'd agree that this isn't specifically an antipattern. It might be a smell depending upon the usage. There are reasons why one would actually not want to use exceptions (e.g. the errors being returned are not 'exceptional', for starters).

There are instances where you want to have a service return a common model for its results, including both errors and good values. This might be wrapped by a low level service interaction that translates the result into an exception or other error structure, but at the level of the service, it lets the service return a result and a status code without having to define some exception structure that might have to be translated across a remote boundary.

This code may not necessarily be an error either: consider an HTTP response, which consists of a lot of different data, including a status code, along with the body of the response.

云柯 2024-07-13 09:08:05

嗯,这不是反模式。 C++ 标准库利用了此功能,.NET 甚至在 .NET 框架中提供了一个特殊的 FunctionResult 类。 它称为可为空。 是的,这并不限于函数结果,但它可以用于这种情况,并且实际上在这里非常有用。 如果 .NET 1.0 已经有了 Nullable 类,那么它肯定会用于 NumberType.TryParse 方法,而不是 out 参数。

Well, it's not an antipattern. The C++ standard library makes use of this feature and .NET even offers a special FunctionResult class in the .NET framework. It's called Nullable. Yes, this isn't restricted to function results but it can be used for such cases and is actually very useful here. If .NET 1.0 had already had the Nullable class, it would certainly have been used for the NumberType.TryParse methods, instead of the out parameter.

携君以终年 2024-07-13 09:08:05

我通常将有效负载作为(非 const)引用传递,并将错误代码作为返回值传递。

我是游戏开发者,我们消除例外

I usually pass the payload as (not const) reference and the error code as a return value.

I'm a game developer, we banish exceptions

疑心病 2024-07-13 09:08:05

Konrad 是对的,C# 始终使用双返回值。 但我有点喜欢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 模式无法扩展到非值返回类型(即类实例)。 这不适用于 Dictionary.TryGetValue()。 TryGetValue 比 KeyNotFoundException 更好(在调试器中不断出现“第一次机会异常”,可以说更高效),比 Java 的 get() 返回 null 的做法更好(如果需要 null 值怎么办),并且比必须首先调用ContainsKey()。

但这仍然有点奇怪 - 因为这看起来像 C#,所以它应该使用 out 参数。 实例化类可能会损失所有效率提升。

(可能是 Java,除了“string”类型是小写的。在 Java 中,当然你必须使用一个类来模拟双返回值。)

Konrad is right, C# uses dual return values all the time. But I kind of like the TryParse, Dictionary.TryGetValue, etc. methods in C#.

int value;
if (int.TryParse("123", out value)) {
    // use value
}

instead of

int? value = int.TryParse("123");
if (value != null) {
    // use value
}

...mostly because the Nullable pattern does not scale to non-Value return types (i.e., class instances). This wouldn't work with Dictionary.TryGetValue(). And TryGetValue is both nicer than a KeyNotFoundException (no "first chance exceptions" constantly in the debugger, arguably more efficient), nicer than Java's practice of get() returning null (what if null values are expected), and more efficient than having to call ContainsKey() first.

But this is still a little bit screwy -- since this looks like C#, then it should be using an out parameter. All efficiency gains are probably lost by instantiating the class.

(Could be Java except for the "string" type being in lowercase. In Java of course you have to use a class to emulate dual return values.)

雪落纷纷 2024-07-13 09:08:05

我不确定这是一种反模式。 我经常看到出于性能原因使用它而不是异常,或者可能是为了使该方法可能失败的事实更加明确。 对我来说,这似乎是一种个人偏好,而不是一种反模式。

I am not sure this is an anti-pattern. I have commonly seen this used instead of exceptions for performance reasons, or perhaps to make the fact that the method can fail more explicit. To me, it seems to be a personal preference rather than an anti-pattern.

时光清浅 2024-07-13 09:08:05

我同意那些说这不是反模式的人的观点。 在某些情况下,这是一个完全有效的模式。 例外是针对异常情况,返回值(如您的示例中)应在预期情况下使用。 某些领域期望来自类的有效和无效结果,并且这些结果都不应该被建模为例外。

例如,给定 X 量的汽油,汽车能否从 A 到达 B,如果可以,还剩下多少汽油? 这类问题非常适合您提供的数据结构。 无法从 A 到 B 的行程是预料之中的,因此不应使用例外。

I agree with those that say this is not an anti-pattern. Its a perfectly valid pattern in certain contexts. Exceptions are for exceptional situations, return values (like in your example) should be used in expected situations. Some domains expect valid and invalid results from classes, and neither of those should be modeled as exceptions.

For example, given X amount of gas, can a car get from A to B, and if so how much gas is left over? That kind of question is ideal for the data structure you provided. Not being able to make the trip from A to B is expected, hence an exception should not be used.

疏忽 2024-07-13 09:08:05

这种方法实际上比我见过的其他方法要好得多。 例如,C 中的某些函数在遇到错误时会返回并看起来成功。 判断它们失败的唯一方法是调用一个将获取最新错误的函数。

我花了几个小时尝试在 MacBook 上调试信号量代码,最后发现 sem_init 在 OSX 上不起作用! 它编译没有错误,运行也没有引起任何错误 - 但信号量不起作用,我不明白为什么。 我很遗憾那些将使用 POSIX 信号量 的应用程序移植到OSX 必须处理已经调试好的资源争用问题。

This approach is actually much better than some others that I have seen. Some functions in C, for example, when they encounter an error they return and seem to succeed. The only way to tell that they failed is to call a function that will get the latest error.

I spent hours trying to debug semaphore code on my MacBook before I finally found out that sem_init doesn't work on OSX! It compiled without error and ran without causing any errors - yet the semaphore didn't work and I couldn't figure out why. I pity the people that port an application that uses POSIX semaphores to OSX and must deal with resource contention issues that have already been debugged.

浅忆流年 2024-07-13 09:08:05

“无法确定这是否是一个错误”模式怎么样? 似乎如果您确实有异常但想要返回部分结果,则可以将结果包装在异常中。

How about the "Can't decide whether this is an error or not" pattern. Seems like if you really had an exception but wanted to return a partial result, you'd wrap the result in the exception.

空‖城人不在 2024-07-13 09:08:05

如果您不想使用异常,最简洁的方法是让函数返回错误/成功代码,并采用用结果填充的引用或指针参数。

我不会称其为反模式。 这是一种经过充分验证的可行方法,通常比使用异常更可取。

If you don't want to use exceptions, the cleanest way to do it is to have the function return the error/success code and take either a reference or pointer argument that gets filled in with the result.

I would not call it an anti-pattern. It's a very well proven workable method that's often preferable to using exceptions.

过去的过去 2024-07-13 09:08:05

如果您预计您的方法偶尔会失败,但不认为这是例外,我更喜欢 .NET Framework 中使用的这种模式:

bool TryMyFunction(out FunctionResult result){    

     //...    
     result = new FunctionResult();
}

If you expect your method to fail occasionally, but don't consider that exceptional, I prefer this pattern as used in the .NET Framework:

bool TryMyFunction(out FunctionResult result){    

     //...    
     result = new FunctionResult();
}
呆橘 2024-07-13 09:08:05

关于气味和反模式的争论让我想起了“幸存者”电视节目,其中有各种编程结构试图互相投票离开岛屿。 我更愿意看到“构建 X 有如此这般的优点和缺点”,而不是一个不断发展的关于应该做什么和不应该做什么的法令列表。

Debates about smells and anti-patterns remind me the "Survivor" TV shows, where you have various programming constructs trying to vote each other off the island. I'd prefer to see "construct X has such-and-so pros and cons", rather than a continually evolving list of edicts of what should and should not be done.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文