异常处理放置 - C#

发布于 2024-10-30 13:29:33 字数 1772 浏览 3 评论 0原文

我决定删除代码中的一些 using 语句,以便我可以捕获特定异常并手动处理资源的处置。我重构了一些代码,使其更具可读性和可维护性,在实现新的 try/catch 块之后,我想知道它们是否已正确放置以完成手头的任务。

示例:

public static DataTable Select(string table, string[] column, Object operand)
{
        DataTable dTable = null;
        SQLiteConnection connection = null;
        SQLiteCommand command = null;
        SQLiteDataReader dReader = null;

        //convert to array for arguments
        StringBuilder query = new StringBuilder();
        query.Append("select ");

        for (int i = 0; i < column.Length; i++)
        {
            query.Append(column[i]);

            if (i < column.Length - 1)
            {
                query.Append(",");
            }
        }
        query.Append(" from ");
        query.Append(table);

        try
        {
            connection = new SQLiteConnection(_connectionString);
            command = new SQLiteCommand(query.ToString(), connection);
            dTable = new DataTable();

            connection.Open();

            dReader = command.ExecuteReader();

            dTable.Load(dReader);

            return dTable;
        }
        catch (SQLiteException sqle)
        {
            //Handle exception
        }
        finally
        {
            connection.Dispose();
            command.Dispose();
            dReader.Dispose();
            dTable.Dispose();
        }
        return null;
}

在此示例中,我仅实现了 SQL 操作本身的 try/catch,我这样做是因为它确保可以记录引发的任何异常并正确处理资源。然后我注意到这使得 for 循环对异常开放,尽管提供的索引器将受到保护并通过 GUI 创建。

我是否明智地将整个方法封装在 try/catch 语句中,或者我是否过于谨慎?您可以说我正在寻找管理语句本身放置的最佳实践。

感谢您抽出时间!

编辑:

我知道 using 语句在处理资源的处置和管理方面是理想的选择,但是正如问题开头提到的,我希望能够捕获特定类型的异常,在特别是那些从 SQLite 组件生成的。

I've decided to remove some of the using statements in my code so I can catch specific exceptions and handle the disposing of resources manually. I have refactored some of the code to make it more readable and maintable, after implementing the new try/catch block I am left wondering if they have been placed correctly for the task at hand.

Example:

public static DataTable Select(string table, string[] column, Object operand)
{
        DataTable dTable = null;
        SQLiteConnection connection = null;
        SQLiteCommand command = null;
        SQLiteDataReader dReader = null;

        //convert to array for arguments
        StringBuilder query = new StringBuilder();
        query.Append("select ");

        for (int i = 0; i < column.Length; i++)
        {
            query.Append(column[i]);

            if (i < column.Length - 1)
            {
                query.Append(",");
            }
        }
        query.Append(" from ");
        query.Append(table);

        try
        {
            connection = new SQLiteConnection(_connectionString);
            command = new SQLiteCommand(query.ToString(), connection);
            dTable = new DataTable();

            connection.Open();

            dReader = command.ExecuteReader();

            dTable.Load(dReader);

            return dTable;
        }
        catch (SQLiteException sqle)
        {
            //Handle exception
        }
        finally
        {
            connection.Dispose();
            command.Dispose();
            dReader.Dispose();
            dTable.Dispose();
        }
        return null;
}

In this example I have only implemented the try/catch around the SQL operations themselves, I did this as it ensures any exceptions that are thrown can be noted and the resourced disposed correctly. I then noticed that this left the for loop open to exceptions, although the supplied indexer will be protected and created via a GUI.

Would I be wise to encapsulate the entire method in the try/catch statement or am I being overly cautious? You could say I'm looking for the best practice when it comes to managing the placement of the statements themselves.

Thanks for your time!

Edit:

I know that the using statement would be ideal in terms of handling the disposal and management of resources however as mentioned at the beginning of the question I wish to be able to catch specific types of exceptions, in particular those generated from the SQLite components.

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

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

发布评论

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

评论(6

じее 2024-11-06 13:29:33

不要忘记 null 检查:

finally {
  if (connection != null) connection.Dispose();
  if (command != null) command.Dispose();
  if (dReader != null) dReader.Dispose();
  if (dTable != null) dTable.Dispose();
}

其中一个构造函数可能会引发异常,在这种情况下,对象将不会被初始化。

Don't forget a null check:

finally {
  if (connection != null) connection.Dispose();
  if (command != null) command.Dispose();
  if (dReader != null) dReader.Dispose();
  if (dTable != null) dTable.Dispose();
}

It is possible that one of the constructors throws an exception, in that case the objects will not have been initialized.

孤城病女 2024-11-06 13:29:33

当您关心的是资源管理时,为什么要显式地使用 try/catch 呢?使用 using 代替:

using(SQLiteConnection connection = new SQLiteConnection(_connectionString))
{ 
   ..
   using(SQLiteCommand command = new SQLiteCommand(query.ToString(), connection))
   {
      using(SQLiteDataReader  reader = dReader = command.ExecuteReader())
      {
          dTable.Load(dReader);
      }
   }
}

目前您还返回 dTable,但您将其放置在 finally 块中。

Why use try/catch explicitly when what you are concerned about is resource management? Use using instead:

using(SQLiteConnection connection = new SQLiteConnection(_connectionString))
{ 
   ..
   using(SQLiteCommand command = new SQLiteCommand(query.ToString(), connection))
   {
      using(SQLiteDataReader  reader = dReader = command.ExecuteReader())
      {
          dTable.Load(dReader);
      }
   }
}

Also currently you are returning dTable, but you are disposing it in your finally block.

新雨望断虹 2024-11-06 13:29:33

如果您认为有可能抛出超出数据库问题范围的异常,则可以将整个方法包含在 try/catch 中。您可以根据捕获的内容轻松区分异常。例如:

DataTable dTable = null;
SQLiteConnection connection = null;
SQLiteCommand command = null;
SQLiteDataReader dReader = null;

try
{
  // non-DB code

  // DB code
}
catch (SQLiteException sqle)
{
  // Handle DB exception
}
catch (IndexOutOfRangeException ie)
{
  // If you think there might be a problem with index range in the loop, for example
}
catch (Exception ex)
{
  // If you want to catch any exception that the previous catches don't catch (that is, if you want to handle other exceptions, rather than let them bubble up to the method caller)
}
finally
{
  // I recommend doing some null-checking here, otherwise you risk a NullReferenceException.  There's nothing quite like throwing an exception from within a finally block for fun debugging.
  connection.Dispose();
  command.Dispose();
  dReader.Dispose();
  dTable.Dispose();
}
return null;

You could enclose the entire method in a try/catch if you think that there's any likelihood that exceptions will be thrown outside of the scope of database problems. You can easily differentiate the exceptions by what you catch. For example:

DataTable dTable = null;
SQLiteConnection connection = null;
SQLiteCommand command = null;
SQLiteDataReader dReader = null;

try
{
  // non-DB code

  // DB code
}
catch (SQLiteException sqle)
{
  // Handle DB exception
}
catch (IndexOutOfRangeException ie)
{
  // If you think there might be a problem with index range in the loop, for example
}
catch (Exception ex)
{
  // If you want to catch any exception that the previous catches don't catch (that is, if you want to handle other exceptions, rather than let them bubble up to the method caller)
}
finally
{
  // I recommend doing some null-checking here, otherwise you risk a NullReferenceException.  There's nothing quite like throwing an exception from within a finally block for fun debugging.
  connection.Dispose();
  command.Dispose();
  dReader.Dispose();
  dTable.Dispose();
}
return null;
一身仙ぐ女味 2024-11-06 13:29:33

当您考虑中间实体之一的创建失败时会发生什么时,您会发现此重构带来的一个更大问题。例如,如果连接创建抛出异常,那么尝试对所有这些 null 变量调用 Dispose 的 finally 块中抛出的异常会发生什么情况?至少事先检查是否为空,或者在finally中添加一个额外的try/catch。我想说您可以从使用 Resharper 中受益,它已经指出了这些问题。

A bigger problem you've introduced with this refactoring can be seen when you consider what will happen when the creation of one of the intermediate entities fails. For example, if the connection creation throws, then what happens to the exception thrown in your finally block that attemts to call Dispose on all those null variables? At least check for null beforehand, or put an additional try/catch inside your finally. I'd say you could benefit from the use of Resharper, which would have already pointed out these issues.

长伴 2024-11-06 13:29:33

我不知道这是否是最佳实践,但我通常在访问外部资源(例如数据库访问、文件 I/O 等)的代码块周围放置 try/catch 语句,这可能会由于各种原因(无法访问的资源)而抛出异常、I/O 错误等)。我不保护我所控制的代码 - 这就是单元测试发挥作用的地方

顺便说一句:您知道可以用 string.Join() 替换循环吗?

更新:只是为了澄清:只有当您想捕获特定异常并执行一些自定义逻辑时,try/catch 块才真正有意义。否则,您应该坚持 using 并让异常冒泡并在适当的位置处理它(例如通知用户由于服务器不可用等原因无法保存某些数据)

I don't know if it is best practice but I usually put try/catch statements around blocks of code where external resources are accessed like database access, file I/O, etc. which might spit out exceptions due to various reason (inaccessible resource, I/O error, etc.). I don't protect code which I'm in control of - that's where unit tests come into place

Btw: You know that you can replace your loop with string.Join()?

Update: Just to clarify: try/catch blocks only really make sense if you want to catch specific exception and execute some custom logic. Otherwise you should stick to using and let the exception bubble up and deal with it at the appropriate place (e.g. notify the user that some data could not be saved because the server is unavailable or so)

浪漫人生路 2024-11-06 13:29:33

如果您所担心的只是正确处置东西,那么您应该为此使用“使用”块。 http://msdn.microsoft.com/en-us/library/yh598w02.aspx

If all you are worried about is properly disposing of things, you should be using a 'using' block for this. http://msdn.microsoft.com/en-us/library/yh598w02.aspx

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