2011-04-03 21 views
2

我決定刪除我的代碼中的一些使用語句,所以我可以捕獲特定的異常並處理手動處理資源。我已經重構了一些代碼,使它更具可讀性和可維護性,在實現了新的try/catch塊之後,我仍然想知道它們是否已經正確地放置在手頭的任務上。異常處理的位置 - C#

例子:

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; 
} 

在這個例子中,我只實現的try/catch周圍的SQL操作本身,我這樣做是因爲它確保了被拋出可以注意到和資源配置的任何異常正確。然後我注意到這會讓for循環打開異常,儘管提供的索引器將通過GUI進行保護和創建。

我是明智的將整個方法封裝在try/catch語句中,還是我過於謹慎?當涉及到管理報表本身的位置時,您可以說我正在尋找最佳實踐。

謝謝你的時間!

編輯:

我知道using語句將是理想的處理處置和資源管理方面然而,由於在這個問題開頭提到我希望能夠捕獲特定類型的異常,特別是從SQLite組件生成的異常。

+0

備註:您使用字符串連接來構建查詢,因此請小心這裏的SQL注入攻擊。在這種方法之外,傳遞給它的參數需要提前檢查問題可能並不明顯。直覺上,我期望數據訪問類來處理,但這不是。 – David 2011-04-03 20:37:11

+0

我在所有方法中使用參數化查詢,列由GUI生成,不能通過用戶輸入手動輸入。感謝指針雖然:) – 2011-04-03 21:48:50

回答

2

如果您認爲有可能將異常拋出數據庫問題範圍之外,您可以將整個方法放在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; 
+0

正是我需要知道的,清晰而簡單。謝謝! – 2011-04-03 22:12:38

8

不要忘記null檢查:

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

這可能是一個構造函數拋出異常,在對象不會被初始化的情況。

+0

啊,很好的抓住哈哈!謝謝。 – 2011-04-03 21:55:30

1

你用這個重構推出一個更大的問題可能是當你考慮當中間實體之一的創建失敗會發生什麼事情可以看出。例如,如果連接創建拋出,那麼finally塊中拋出的異常會發生什麼情況,試圖對所有這些空變量調用Dispose?至少要事先檢查一下null,或者在你的終端裏放一個try/catch。我會說你可以從使用Resharper中受益,而這將會指出這些問題。

1

我不知道這是否是最佳做法,但我通常會將try/catch語句放在可訪問外部資源的代碼塊中,如數據庫訪問,文件I/O等,這些可能會因各種原因原因(資源不可訪問,I/O錯誤等)。我不保護我控制的代碼 - 這就是單元測試到位的地方

btw:你知道你可以用string.Join()替換你的循環嗎?

更新:只是澄清:try/catch塊只有真正有意義,如果你想捕捉特定的異常並執行一些自定義邏輯。否則,你應該堅持using,讓異常冒泡並在適當的地方處理它(例如通知用戶某些數據因爲服務器不可用等原因而無法保存)

3

爲什麼使用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塊處置它。

+1

有點愚蠢,你可以解釋如何使用'using'語句,當他說他曾經使用它們,但刪除它們。他還給出了刪除「使用」陳述的理由。你真的讀過他的帖子嗎? – 2011-04-03 21:06:17

+0

我想我確實忽略了這句話 - 仍然對我沒有意義 - try/catch並不禁止你使用'using'語句,你可以同時執行這兩個操作。 – BrokenGlass 2011-04-03 21:16:07

+1

當你有一個try-finally場景時,你需要'using'語句。如果你有一個try-catch-finally的場景,我認爲不使用'using',而是使用你必須放在那裏的結構是完全有效的。 – Jan 2011-04-03 21:32:46