2010-10-14 31 views
14

以下代碼會生成兩個CA2000警告(其中包括但不是重點)。如何在所有權轉移後襬脫CA2000警告?

public sealed class Item: IDisposable 
{ 
    public void Dispose() {} 
} 

public sealed class ItemContainer 
{ 
    public void Add(Item item) 
    { 
    } 
} 

public sealed class Test: IDisposable 
{ 
    private ICollection<Item> itemCollection; 
    private ItemContainer itemContainer; 

    private void Add(Item item) 
    { 
     itemCollection.Add(item); 
    } 

    public void Initialize() 
    { 
     var item1 = new Item(); // no warning 
     itemCollection.Add(item1); 

     var item2 = new Item(); // CA2000: call Dispose on object item2 
     Add(item2); 

     var item3 = new Item(); // CA2000: call Dispose on object item3 
     itemContainer.Add(item3); 
    } 

    public void Dispose() {} 
} 

請注意,沒有爲item1生成警告。看起來,代碼分析假定ICollection將承擔該項目的責任,並最終處置它。

有沒有一種方法,以紀念我的Add方法,從而使警報消失?

我在找尋類似於CA1062的ValidatedNotNullAttribute

編輯:說清楚:這不是我真正的代碼。在真實的代碼中,一切都妥善處理。

這只是CA不承認,打到我Add方法轉移所有權。 我希望它能夠像處理ICollection.Add一樣對待我的Add方法。

在同一範圍內處置不是一種選擇。

回答

6

我也問了這個在connect.microsoft.com而這也正是他們回答:

您可以通過具有容器/集合對象,增加了一次性對象實現的ICollection或ICollection的<牛逼>解決該問題。執行添加的方法也必須具有以「添加」開頭的名稱。

當然,當class Test實現ICollection <Item>時,警告消失。對於這種情況,這是一個可接受的解決方案。但是,如果實施ICollection來表明所有權轉讓並不合適,那麼該做什麼仍然是一個懸而未決的問題。

public sealed class Test: IDisposable, ICollection<Item> 
{ 
    public void Initialize() 
    { 
     var item1 = new Item(); // no warning 
     itemCollection.Add(item1); 

     var item2 = new Item(); // no warning 
     ((ICollection<Item>)this).Add(item2); 

     var item3 = new Item(); // no warning 
     AddSomething(item3); 
    } 

    //... implement ICollection and Method AddSomething 
} 
+0

接受我自己的答案,因爲這是我在這種情況下所做的:在已實現IDisposable的類上實現ICollection。我完全同意Damien的觀點:如果CA需要IDisposable和ICollection,那將更有意義。 – Henrik 2010-10-23 07:19:38

+0

有什麼辦法可以通過索引在一次性物品字典上實現類似的東西嗎? – Dave 2018-03-02 10:20:34

9

你想修復代碼還是隻是壓制警告?抑制警告很簡單:

[SuppressMessage("Microsoft.Reliability", 
       "CA2000:DisposeObjectsBeforeLosingScope", 
       Justification = "Your reasons go here")] 
public void Initialize() 
{ 
    // ... 
} 
+2

我寧願看到這樣的理由,所以stylecop。 – annakata 2010-10-14 10:41:04

+1

@annakata:我也會這樣編輯它來包括它...... – LukeH 2010-10-14 10:45:07

+1

我寧願不壓制警告。如果該方法稍後修改,我希望在適當的時候發出警告。 – Henrik 2010-10-14 10:47:14

1

當然,要做的第一件事就是實際上有Dispose方法清理集合的成員。我假設這只是示例中的錯誤,而不是真正的代碼。

除此之外,我只是壓制警告。我非常強烈地認爲,任何壓制:

  1. 應該是一個非常短的範圍,所以它不會抑制另一個是真正的錯誤警告的情況。
  2. 應該註釋一個評論,不管死亡如何明顯,看起來警告是安全的壓制。

這就是說,我認爲CA2000的分析很差,不值得讓它默認檢查,但只是在偶爾的評論。經過一定數量的誤報後,警告甚至不會再被視爲警告,只是噪聲隱藏了真實的警告,因此使代碼更有可能成爲越野車。

6

我知道這是示例代碼,所以這個解決方法是否會在你的真實代碼中工作,我不能說。

在這種特殊情況下,如果您將對象創建代碼移入其自己的方法中,並返回新的Item,則警告消失,例如,更改:

public void Initialize() 
{ 
    var item1 = new Item(); // no warning 
    itemCollection.Add(item1); 

    var item2 = CreateItem(); // CA2000 no longer appears 
    Add(item2); 

    var item3 = new Item(); // CA2000: call Dispose on object item3 
    itemContainer.Add(item3); 
} 

private Item CreateItem() 
{ 
    return new Item(); 
} 

很明顯,CreateItem方法可以傳遞任意參數傳遞給Item構造函數。

編輯

在看到Henrik的回答,並在連接反應,我可以說的是bletch。不能保證ICollection實現也實現了IDisposable,雖然他的發佈示例確實實現了IDisposable,但顯然這並不需要關閉代碼分析(如果必須實現這兩者,我還是會有點不錯)。一個實現ICollection但不實現IDisposable的類很難處理正確處理包含的對象。

+0

但是在這種情況下,即使刪除了Add(item2)並且item2可驗證地不處理,警告也不會出現。所以我可能只是壓制警告。 – Henrik 2010-10-18 12:17:07

+0

@亨利克 - 我花的時間越多,我越感到困惑。不能保證任何特定的ICollection實現將正確地處理添加到它的項目,所以我一直在想,爲什麼我們不能*獲取項目1的CA2000。 – 2010-10-19 06:28:26

+0

獲得此答案的賞金。這在CreateItem方法內部將該項目添加到集合以確保它已丟棄的情況下可能很有用。 – Henrik 2010-10-23 07:18:46