2013-02-12 56 views
9

我有類似於以下代碼。在類級變量上使用using語句是不好的做法嗎?

class MyController 
{ 
    [ThreadStatic] private DbInterface db; 

    public void ImportAllData() 
    { 
     using (db = new DbInterface()) 
     { 
      var records = PullData(); 
      PushData(records); 
     } 
    } 

    private DbRecord[] PullData() 
    { 
     return db.GetFromTableA(); 
    } 

    private void PushData(DbRecord[] records) 
    { 
     db.InsertIntoTableB(records); 
    } 
} 

另一種方法是維護起來很麻煩。

class MyController 
{ 
    public void ImportAllData() 
    { 
     using (var db = new DbInterface()) 
     { 
      var records = PullData(db); 
      PushData(records, db); 
     } 
    } 

    private DbRecord[] PullData(DbInterface db) 
    { 
     return db.GetFromTableA(); 
    } 

    private void PushData(DbRecord[] records, DbInterface db) 
    { 
     db.InsertIntoTableB(records); 
    } 
} 

據我所看到的,我的第一個執行:

  • 是線程安全的(假設DbInterface是線程安全的),
  • 防止任何其它進程從觸摸db變量,
  • 確保db將始終處置,即使在例外情況下也是如此。

對類範圍的變量使用using語句是不好的做法嗎?我錯過了什麼嗎?

+0

考慮使用擴展?或者你打算做很多事情。 – 2013-02-12 00:51:54

+3

有趣的是,如果你曾經做過Win Forms繪畫代碼,那麼OnPaint和Paint事件就非常像這樣,至少在將參考傳遞給使用塊之外。您傳遞的是分配給您的圖形上下文,其管理/處置由調用者處理,因此您不會將其自行處理爲實際的繪製方法。 – tcarvin 2013-02-12 00:57:19

+0

@DanSaltmer,我打算在其他控制器中使用'DbInterface'類。我希望控制器可以訪問所有'DbInterface'方法,但我不想讓控制器知道其他私有方法。據我的理解,擴展方法將適用於所有'DbInterface'實例。或者我誤解了你? – 2013-02-12 01:03:12

回答

10

個人而言,我更喜歡你的第二個選項。

第一個設計的問題是,您有效地爲設計添加了不必要的耦合。您的PullDataPushData方法不能單獨使用 - 他們要求呼叫ImportAllData或其他一些方法,將設置和正確清理變量db首先被調用。

第二個選項,雖然略微更多的代碼(雖然不是很多),使每個方法的意圖非常清楚。每種方法都知道它需要在傳入其中的外部實例上工作。未來很少或根本沒有機會被濫用。

8

您的第一個變體在using塊管理的範圍之外暴露了db。這打開了意想不到的副作用的可能性。例如,另一種方法可能會使用甚至處理db。如果您或稍後的維護人員忘記了db的隱式合同,或甚至通過代碼中的拼寫錯誤,則可能會發生這種情況。

我不會使用第一個變體。

4

下面是一個替代:

sealed class MyImporter 
{ 
    private readonly DbInterface db; 

    public MyImporter(DbInterface db) 
    { 
     this.db = db; 
    } 

    public void ImportAllData() 
    { 
     var records = PullData(); 
     PushData(records); 
    } 

    private DbRecord[] PullData() 
    { 
     return db.GetFromTableA(); 
    } 

    private void PushData(DbRecord[] records) 
    { 
     db.InsertIntoTableB(records); 
    } 
} 

在這種情況下,保持在參考是類責任的清晰部分。它現在也將處置責任推給用戶。這個更加明確的構造減少了向'Controller'添加附加功能的誘惑,這是您的第一種方法在長期內可能變壞的原因。實質上,我們將Import函數重構爲一個單獨的類,以便共享字段訪問不再成爲問題。

+1

+1:我也將依賴注入添加到構造函數中:public MyImporter(DbInterface _db) { db = _db;} – horgh 2013-02-12 01:07:10

+0

@KonstantinVasilcov,同意,這實際上更清潔;它實際上消除了在課堂上進行處置的需要,以及 – 2013-02-12 01:09:07

+0

這將處理db的責任移交給調用者。可能是好事還是壞事,但是這是對班級責任的改變。如果調用者不知道如何創建'db'的實例,這種模式將無法工作。 – 2013-02-12 01:23:53

0

這就是結構在那裏。由於約定規定屬性訪問是輕量級的,並且當用戶認爲他們只是訪問變量時,並不一定要觸發create-dispose循環,所以我會注意將使用置入屬性。

但是下面有關代碼結構的註釋很重要 - 如果您想要導入一次,它將成爲用戶需要了解的設置步驟。如果您可以設想不同的訪問模式,則依賴注入設置允許用戶控制連接的創建和處置。

相關問題