“使用异常来控制流”的示例

时间:2010-07-15 20:18:06

标签: c# exception exception-handling

“使用异常来控制流程”的代码是什么样的?我试图找到一个直接的C#示例,但不能。为什么不好?

由于

9 个答案:

答案 0 :(得分:13)

根据定义,异常是在软件正常流程之外发生的事件。我的头顶快速示例是使用FileNotFoundException来查看文件是否存在。

try
{
    File.Open(@"c:\some nonexistent file.not here");
}
catch(FileNotFoundException)
{
    // do whatever logic is needed to create the file.
    ...
}
// proceed with the rest of your program.

在这种情况下,您没有使用File.Exists()方法来实现相同的结果,但没有异常的开销。

除了使用不当外,还存在与异常相关的开销,填充属性,创建堆栈跟踪等。

答案 1 :(得分:10)

以下代码捕获了一个可以轻松完全避免的异常。这使得代码更难以遵循,并且通常也会产生性能成本。

int input1 = GetInput1();
int input2 = GetInput2();

try
{
    int result = input1 / input2;
    Output("{0} / {1} = {2}", input1, input2, result);
}
catch (OverflowException)
{
    Output("There was an overflow exception. Make sure input2 is not zero.");
}

更好

此代码检查抛出异常的情况,并在错误发生之前更正情况。这样就没有例外。代码更易读,性能很可能更好。

int input1 = GetInput1();
int input2 = GetInput2();

while (input2 == 0)
{
    Output("input2 must not be zero. Enter a new value.");
    input2 = GetInput2();
}

int result = input1 / input2;
Output("{0} / {1} = {2}", input1, input2, result);

答案 2 :(得分:9)

它大致等同于goto,除了“Exception”这个词更糟糕,并且开销更大。你告诉代码跳转到catch块:

bool worked;
try
{
    foreach (Item someItem in SomeItems)
    {
        if (someItem.SomeTestFailed()) throw new TestFailedException();
    }
    worked = true;
}
catch(TestFailedException testFailedEx)
{
    worked = false;
}
if (worked) // ... logic continues

正如您所看到的,它正在运行一些(补偿)测试;如果失败,则抛出异常,worked将设置为false

当然,直接更新bool worked要容易得多!

希望有所帮助!

答案 3 :(得分:5)

这是一个常见的:

public bool TryParseEnum<T>(string value, out T result)
{
    result = default(T);

    try
    {
        result = (T)Enum.Parse(typeof(T), value, true);
        return true;
    }
    catch
    {
        return false;
    }
}

答案 4 :(得分:2)

可能是我见过的最严重的违规行为:

// I haz an array...
public int ArrayCount(object[] array)
{
    int count = 0;
    try
    {
        while (true)
        {
            var temp = array[count];
            count++;
        }
    }
    catch (IndexOutOfRangeException)
    {
        return count;
    }
}

答案 5 :(得分:2)

我目前正在使用第三方程序执行此操作。它们有一个“游标”接口(基本上是一个IEnumerable替代品),告诉程序你完成的唯一方法是引发一个异常。代码基本上看起来像:

// Just showing the relevant section
bool finished = false;

public bool IsFinished()
{
    return finished;
}

// Using something like:
// int index = 0;
// int count = 42;

public void NextRecord()
{
    if (finished)
        return;

    if (index >= count)
        throw new APIProgramSpecificException("End of cursor", WEIRD_CONSTANT);
    else
        ++index;
}

// Other methods to retrieve the current value

毋庸置疑,我讨厌 API - 但它是流量控制例外(以及疯狂的工作方式)的一个很好的例子。

答案 6 :(得分:1)

一个例子是使用异常从递归方法返回结果:

public void Search(Node node, object data)
{
    if(node.Data.Equals(data))
    {
        throw new ResultException(node);
    }
    else
    {
        Search(node.LeftChild, data);
        Search(node.RightChild, data);
    }    
}

出于某些原因,做这样的事情是个问题。

  1. 这完全是违反直觉的。例外是针对特殊情况而设计的。按预期工作的东西应该(我们希望)永远不会是一个特例。
  2. 您不能总是依赖抛出并传播给您的异常。例如,如果抛出异常的代码在一个单独的线程中运行,则需要一些额外的代码来捕获它。
  3. 这是一个潜在的性能问题。有一些与异常相关的开销,如果你扔了很多,你可能会看到你的应用程序性能下降。
  4. 还有一些关于这个主题的例子和一些有趣的讨论here

    免责声明:上述代码改编自该维基页面上的第一个示例,将其转换为C#。

答案 7 :(得分:1)

我不喜欢C#,但你可以看到 try-catch-finally 语句和普通控制流语句 if-then-else 之间有一些相似之处。

当您throw出现异常时,请考虑强制将控件传递给catch子句。所以,如果你有

if (doSomething() == BAD) 
{
  //recover or whatever
}

您可以通过try-catch轻松地想到它:

try
{
  doSomething();
}
catch (Exception e)
{
  //recover or do whatever
}

关于异常的强大之处在于你不必在同一个体内改变程序的流程,你可以随时抛出一个异常,保证控制流会突然发散并到达捕获条款。这很强大但同时也很危险,因为你可以完成最后需要备份的操作,这就是finally语句存在的原因。

此外,您还可以在没有有效使用条件的情况下对while语句进行建模:

while (!finished)
{
  //do whatever
}

可以成为

try
{
  while (true)
  {
     doSomethingThatEventuallyWillThrowAnException();
  }
}
catch (Exception e)
{
  //loop finished
}

答案 8 :(得分:1)

合作伙伴开发的模块导致我们的应用程序需要很长时间才能加载。经过仔细研究,该模块正在寻找app启动时的配置文件。这本身并不太令人讨厌,但它的做法却非常糟糕:

对于app目录中的每个文件,它打开文件并尝试将其解析为XML。如果一个文件引发异常(因为它不是XML),它会捕获异常,压制它并尝试下一个文件!

当合作伙伴测试此模块时,他们在app目录中只有3个文件。 bonehead配置文件搜索对测试应用启动没有明显影响。当我们将它添加到我们的应用程序时,app目录中有100个文件,并且应用程序在启动时冻结了近一分钟。

要向伤口添加盐,模块正在搜索的配置文件的名称是预先确定的并且是常量。不需要任何文件搜索。

天才有其局限性。愚蠢是无限的。