是否可以将网络异常用于控制流程?

时间:2011-02-15 17:57:58

标签: .net sockets exception-handling

我今天正在做一些.NET编码,我遇到了一些我以前没想过的东西 - 许多微软用于测试网络连接的内置方法(ping,TCP套接字等)都非常自由地投掷如果连接失败,则为例外。

当然,在一般情况下,在程序的控制流程中使用异常并不好。我很好奇 - 如果.NET库如此容易抛出它们,我怎么能避免这样的事情(借口可能是凌乱的代码,只是抛出一个例子):

bool TestConnection(string host)
{
    bool connected;

    Ping ping = new Ping();
    PingReply reply = ping.Send(host);

    connected = (reply.Status == IPStatus.Success);

    return connected; // possibly won't return false because of exceptions
}

我可以使用try-catch块来处理异常,但我要做的就是将connected设置为false。因为我从异常中丢弃了所有信息,所以这基本上不是完全吞下了这个例外吗?这里最好的做法是什么?

4 个答案:

答案 0 :(得分:1)

你一定要抓住.NET Framework抛出的异常并且不要假设你唯一能做的就是返回false,这取决于你的应用程序设计和用例你可能会重新抛出异常并通知上层那个例如,输入的网络路径不再存在,或者您返回false并在其他情况下忽略该问题。

.NET Framework是我们用来构建东西的基础,必须是通用的,如果你试图打开一个不存在的文件,它会抛出FileNotFoundException然后在某些情况下你创建它,在其他一些情况下你告诉它用户无法找到文件...它总是取决于您自己的代码,基本的例外应该通过防御方法避免或被捕获。 :)

答案 1 :(得分:0)

您应该避免使用控件流的例外(如果可能)。例如,使用 TryParse 而不是Parse,检查正确的类型或非空格,而不是捕获null引用或类型转换异常。

但在这种情况下您没有其他API 可用,因此您必须使用可用的API。请注意,TestConnection中的未捕获异常只是意味着您的函数的调用者必须执行此操作,这将是更大的邪恶

答案 2 :(得分:0)

这取决于方法的目的。例如,如果您只想获取bool来确定是否可以建立连接,请捕获异常并返回false。

bool CanConnect(string host)
{
    bool connected;

    Ping ping = new Ping();

    try
    {
        PingReply reply = ping.Send(host);
    }
    catch(/*catch the specific exception(s) here*/)
    {
        return false;
    }

    connected = (reply.Status == IPStatus.Success);

    return connected; // possibly won't return false because of exceptions
}

但是,如果您想要测试连接并提供更具体的错误,说明连接失败的原因,那么您不希望在此方法中捕获异常。你可以通过允许异常冒泡来让调用者确切地知道出了什么问题。

这与Microsoft的异常处理指南一致:

  

不要过度使用捕获物。通常应该允许异常向上传播调用堆栈。   捕获您无法合法处理的异常会隐藏关键的调试信息。

(来自MS Exception Handling Guidelines

这不是使用异常来操纵控制流。 This answer给出了一个使用控制流异常的例子。

答案 3 :(得分:0)

你在使用什么连接?您应该使用该类的方法,而不是尝试使用Ping进行预测试。然后,在抛出任何连接失败时处理它们。

  

在一般情况下,在程序的控制流程中使用异常并不好

有时您会捕获异常并将其用于控制​​流程。当架构更改或Try - 样式方法(例如int.TryParse)存在时,您不应该这样做,并且您当然应该在必须具有高性能的任何代码路径上避免它。

Sometimes you must do evil things。 (是的,这是一个C ++常见问题解答,但它是一般编程规则)。

另外 - 如果可以避免,请不要抓住Exception。捕获特定的派生异常类型。如果你编写一个catch块,你最好能够在该位置处理该异常,或者重新使用throw;(而不是throw new ...)。