程序化检查或尝试...捕获

时间:2015-04-13 19:02:57

标签: c# exception-handling

我在这里有一些代码:

public static void OpenConnection(IDbConnection connection)
{
    if(connection == null)
        throw new ArgumentNullException("connection", "The connection was null.");

    if (connection.State != ConnectionState.Closed)
        connection.Close();
}

由于每次在数据库中执行某些操作时打开和关闭连接,因此必须执行相当多的代码。我想知道下一个代码是否会更好地解决性能问题:

public static void OpenConnection(IDbConnection connection)
{
    try
    {
        connection.Close();
    }
    catch (NullReferenceException nullReferenceException) { throw; }
    catch (Exception exception) { } // This will occur if the connection was already closed so nothing should be done then.
}

PS。 catch (Exception exception) { }是否必要?

编辑:在第二段代码中将ArgumentNullException替换为NullReferenceException,因为这将是connection == null时的例外情况。

4 个答案:

答案 0 :(得分:3)

  

我想知道下一个代码是否会更好地解决方案性能

考虑每种情况下的性能和功能差异:

  1. connection为空
  2. 您将获得NullReferenceException而不是ArgumentNullException,这是一个功能差异,因为您获得了不同的异常类型(以及 less 上下文关于异常的原因/位置发生)。如果您决定捕获NullReferecenException并抛出ArgumentNullException,那么您将面临抛出异常的开销,因此会遇到性能损失。

    1. 连接未关闭。
    2. 尝试关闭连接 - 这里没有真正的性能或功能差异。

      1. 连接已关闭
      2. 您尝试再次关闭连接。这里可能不是一个巨大的功能差异(因为如果你试图关闭已经关闭的连接,大多数提供商可能不会生气),但它不需要和可能会有一些性能劣势,具体取决于实际 Close()方法。

        因此,您的第二种方法存在功能差异,实际上可能具有缺点性能。

        坚持使用更清晰地说明预期行为的代码 - 然后只有在您有可衡量的,可纠正的性能问题时才进行优化。

答案 1 :(得分:2)

除了JDB关于异常成本高昂的论点之外,请仔细查看您的代码并告诉我哪些代码更易于阅读/遵循?

如果您从未见过某种方法,并且以"尝试"你真的需要思考并仔细看看。但是,如果它以你的保护条款(if(连接== null)部分)开始,顺便说一下这是一件很常见的事情,你会立即看到,如果你通过null,你甚至不必考虑进入方法你会得到一个例外。把这个保护条款作为合同。你永远不希望在那里传递null。这是更好的设计。

关于PS'。如果你这样做,请记住connection.Close()中可能引发的所有其他异常将被捕获,除非你完成,否则永远不会浮出水面。这样的事情可能会使您的应用程序产生很难追踪的错误。

答案 2 :(得分:1)

根据微软的说法,例外是一个巨大的性能影响。在合理的时候尽量避免使用它们:

  

抛出异常可能非常昂贵,因此请确保不要丢弃很多异常。使用Perfmon查看应用程序抛出的异常数量。您可能会惊讶地发现应用程序的某些区域会产生比预期更多的异常。为了获得更好的粒度,您还可以使用性能计数器以编程方式检查异常编号。

     

查找和设计异常繁重的代码可以获得良好的性能。 请记住,这与try / catch块无关:只有在抛出实际异常时才会产生成本。您可以根据需要使用尽可能多的try / catch块。无偿使用例外是您失去性能的地方。例如,您应该远离诸如使用控制流异常之类的事情。

     

https://msdn.microsoft.com/en-us/library/ms973839.aspx#dotnetperftips_topic2

你的第二个例子实际上是一个更糟糕的情况。你几乎不应该抓住一般例外。你可能认为你知道会抛出什么,但很可能会抛出意外的东西,导致系统不稳定和可能的数据丢失/损坏。

  

使用Catch仍然错误(例外e)

     

尽管CLR异常系统将最坏的异常标记为CSE,但在代码中编写catch(Exception e)仍然不是一个好主意。例外代表了一系列意外情况。 CLR可以检测到最坏的异常 - 指示可能损坏的进程状态的SEH异常。但是,如果忽视或一般性地处理其他意外情况仍然有害。

     

在没有进程损坏的情况下,CLR提供了一些关于程序正确性和内存安全性的强有力保证。执行用安全的Microsoft中间语言(MSIL)代码编写的程序时,您可以确定程序中的所有指令都将正确执行。但是,执行程序指令所要做的事情通常不同于程序员想要做的事情。根据CLR完全正确的程序可能会破坏持久状态,例如写入磁盘的程序文件。

     

https://msdn.microsoft.com/en-us/magazine/dd419661.aspx

答案 3 :(得分:1)

您的第二个解决方案对性能不是更好,因为当尝试阻止导致异常时,您的应用程序将更加努力, catch 块将尝试捕获异常。但第二种解决方案在逻辑点上要好得多。

在您的第一个解决方案中,当连接为空时,您将在第一次检查时收到错误。

Try-Catch或Try-Catch-Finally是处理错误的强大工具,但它们很昂贵。查看此链接,了解您可以使用它执行的操作:Using Try... Catch..., Finally!

为了获得更好的性能,我会使用:

private static void OpenSqlConnection(string connectionString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    //Do some work
}
}

上面的示例创建了一个SqlConnection,打开它,做了一些工作。 使用块结束时连接自动关闭

对于Try-catch的代码,我会做(以捕获异常):

try
{
conn.Close();
}
catch (InvalidOperationException ex)
{
Console.WriteLine(ex.GetType().FullName);
Console.WriteLine(ex.Message);
//for Asp.net app
//Response.Write(ex.GetType().FullName);
// Response.Write(ex.Message);
}

试试看,请参阅:this link - Best Practices for Exceptions