在我抛出异常的情况下,是否应该保留一个无法到达的break语句?

7

我在一个抛出异常的案例中留下了不可达的break语句,这样做是愚蠢的吗? 从防御性的角度来看,如果逻辑发生改变,我希望它还在那里。 另一方面,我不希望其他开发人员在我的代码上看到编译器警告(“检测到不可到达的代码”)。

switch (someInt)
{
    case 1:
        // Do something
        break;
    case 2:
        // Do something else
        break;
    case 3:
        // Oh, we don't use threes here!
        throw new Exception("Business rules say don't use 3 anymore");
        break; // Unreachable...until the fickle business rules change...
    default:
        throw new Exception("Some default exception");
        break; // Unreachable...until...well, you get the idea.
}

该怎么做?

更新

我看到一些回复说在以后删除throw会导致编译器错误。但是,仅仅删除(或注释)throw而没有break跟随它会堆叠情况,可能会导致意外的行为。我不是说这是一个可能发生的情况,但是...防御性编程只是为了应对可能发生的情况吗?


1
不再需要使用 break,我将其删除是因为我使用警告作为错误来构建代码。 - asawyer
1
有趣的问题 - 我最初的反应是包括break语句,但我认为这只是出于习惯。 - KazR
1
如果你认为你的担忧是合理的但不想给别人带来不便,可以使用#pragma warning disable。但过度防御会迅速使你的代码库混乱不堪。 - Michael
9个回答

7

我建议删除它们。原因如下:

  • 目前你不需要它们
  • 看到很多警告总是让我感到紧张,因为你可能会在这种类型的警告噪音中丢失真正的警告(假设你已经关闭了警告作为错误)。

你怎么会错过“真正的错误”呢?要么你的代码无法编译,要么你已经决定警告不是“真正的错误”(即你没有使用“将警告视为错误”的标志进行构建)。 - Michael
1
如果您有150个以上的警告是噪音,并且您引入了一个生成有用警告的东西,那么很容易会错过它。 - gbanfill

7
我不会在switch里“隐藏”它。我会尽快抛出ArgumentExceptions。这样可以避免副作用,也更加透明。
有人可能在switch之前添加代码,使用someInt,即使它是3。
例如:
public void SomeMethod(int someInt)
{
    if (someInt == 3)
        throw new ArgumentException("someInt must not be 3", "someInt");

    switch (someInt)
    {
        // ...
    }
}

2
忽略编译器警告会强化忽略任何编译器警告的不良行为。在我看来,这比保留break语句所获得的任何优势都更加危险。
编辑:我删除了关于编译器强制将break语句放回去的原始观点,如果移除throw语句,则在某些情况下,编译器不会这样做。它只会将该case与下面的case合并。

编译器不会强制要求您添加break,如果该case没有其他代码(在注释掉throw之后)。 - payo
你说得对。在这种情况下,责任在于程序员编写良好的代码。 - FishBasketGordo

2

在生产代码中,我个人不会留下无法到达的代码。在测试时可以这样,但不要让它保持这样。

你不会这样做吧?

public void MyMethodThatThrows()
{
    throw new Exception();
    return;  // unneeded
}

那么为什么要保留break呢?

我很理解这个问题的前半部分,也认为这是一个好观点。然而,举的例子有点牵强附会,因为虽然我不会在 void 函数中使用 return,但我肯定会在 switch 语句中使用 break。当然,这个问题是关于在 switch 中使用 break 而不是 return,因为我是一个只有一个出口的人。 - Tim Lehner
@TimLehner,哈,说得好。我的例子基本上只是为了夸大问题。 - jb.

1

我会把它移除。

这样可以消除警告,即使逻辑改变并且异常被移除,编译器也会报错,提示需要添加break语句。


实际上,有一种情况我们两个都是错的。如果移除异常并且不添加任何内容,那么代码块将会为空,允许无警告或错误地继续执行。 - Ed S.

0

MSDN C# 参考指出:“每个 case 块都必须有一个跳转语句(比如 break 语句),包括最后一个块,无论它是 case 语句还是 default 语句。”

那么,“throw”不是构成“跳转语句”吗?我认为是的。因此,不需要“break”,这个“unreachable”的问题就解决了。 :)


OP承认break并不是必要的,但正在考虑保留它们以作为防御性措施。请考虑如果您决定执行其他操作会发生什么。 - jerry

0
我的防御性想法是将其保留,以防逻辑发生变化。
这里到底有哪些逻辑可能会发生变化?当异常被抛出时会发生什么已经被很好地记录了。而且我认为你可以相当肯定,C#的后续修订不会对“所有已编写的程序都无法正常工作”的破坏性变化产生影响。
即使没有编译器警告,冗余代码也不是一件好事,除非存在这样的可能性,即该代码可能通过在例行维护期间防止错误来发挥作用,在这种情况下,我们不能合理地说存在这样的可能性。

我认为他的意思是,如果异常被删除了,但即使如此,这也不是一个问题,因为你必须有其中之一。 - Ed S.
也许我在那里使用了错误的术语,但是不,我指的不是C#规范的更改,而只是善变的业务规则。 - Tim Lehner

0

我的防御意识想让我把它留在那里,以防逻辑变化。

好吧,如果你删除了 throw 并忘记添加 break,编译器会提醒你。

我认为没有必要放置 break。这是多余的,而且会触发警告,所以我会将其删除。没有理由让无用的代码混淆你的逻辑。


2
仅仅移除 throw 而不加 break 会导致 case 堆叠,这可能是意料之外的行为。 - Tim Lehner
@TimLehner:这是真的,因为正文会是空的。话虽如此...如果您将正文留空,则我认为您这样做是有原因的。我希望您能相信您的同事知道开关的基本工作原理。 - Ed S.
我们不都是希望同样的事情吗,真的吗? :) - Tim Lehner
@TimLehner:嘿嘿,是啊,但说实话...错误难免会发生,这里没有百分之百的傻瓜式选项。如果你有一个经常犯低级错误的开发人员...那就是时候找新员工了。 - Ed S.
如果移除 throw,空 case 中不需要使用 break。请注意,这是针对编程语言的相关内容。 - payo
1
@payo:谢谢你重申这点。 - Ed S.

0

我希望我的项目源代码如此酷且无故障,以至于我不必考虑这些防御性编程的小细节问题 :)

我的意思是,在软件开发中有太多陷阱 - COM 和 Interop、安全/权限和身份验证、证书等等...天哪,我不能告诉你我得写多少代码来避免自己踩到坑里。

只需删除此断点,因为它是多余的,对于那些知道“case”应该以breakreturn结束并且应该对那些不知道这一点的人来说都很明显,这会让他们感到困惑。


没错,这并不是人生中最大的问题。但是,返回时的大小写结尾确实值得讨论... - Tim Lehner

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