2010-05-12 60 views
10

我回到我創建的使用語句中using語句的變量中的變量(聽起來很可笑):返回用於使用使用C#

public DataTable foo() 
{ 
    using (DataTable properties = new DataTable()) 
    { 
     // do something 
     return properties; 
    } 
} 

請問這個處置變量的屬性?

警告34 CA2000:Microsoft.Reliability:

這樣做時仍然收到此警告後在方法「test.test」,所有的引用之前調用System.IDisposable.Dispose的對象「屬性」它超出了範圍。

任何想法?

感謝

+3

無論如何,這只是糟糕的設計,應該返工。 – 2010-05-12 20:56:27

回答

10

如果您想退貨,你不能把它包裝在using語句,因爲一旦你離開了牙套,它超出範圍,並得到處理。

你必須初始化它是這樣的:

public DataTable Foo() 
{ 
    DataTable properties = new DataTable(); 
    return properties; 
} 

,後來打電話就可以了Dispose()

+4

它感覺像'foo()'=='GetUsefulDataTable()'和'using'塊應該是什麼調用這個函數。 – 2010-05-12 20:58:15

9

是的,它會處理它 - 然後返回。這幾乎總是一件壞事。

事實上,對於DataTable,Dispose幾乎從不做任何事情(例外情況是,如果它是遠程的,IIRC),但它仍然是一個普遍的壞主意。通常情況下,您應該將處置的對象視爲不可用。

+0

那麼,從方法返回IDisposable對象而不觸發CA2000警告的正確模式是什麼? – 2011-01-26 14:58:17

+0

@Jhonny:我不知道,說實話 - 我沒有使用過這樣的代碼分析。我預計會有某種方法來壓制警告。 – 2011-01-26 15:19:15

+0

@ JhonnyD.Cano-Leftware-如果您要實例化並返回IDisposable事物,則需要將它們明確地置於代碼中。你的代碼分析「應該」拿起你在別處手動處理。 – IanNorton 2011-11-15 19:33:16

3

使用塊的要點是爲值/對象創建人工範圍。當使用塊完成時,對象被清除,因爲它不再需要。如果你真的想要返回你正在創建的對象,那麼它不是你想要使用的對象。

這將工作得很好。

public DataTable foo() 
{ 
    DataTable properties = new DataTable(); 
    // do something 
    return properties; 
} 
+0

如果它有一個分號,它會正常工作。 = P – Jason 2010-12-10 16:39:18

+0

修正了錯字。 – unholysampler 2010-12-10 16:44:16

1

你的使用使用關鍵字的代碼擴展爲:

{ 
    DataTable properties = new DataTable(); 
    try 
    { 
     //do something 
     return properties; 
    } 
    finally 
    { 
     if(properties != null) 
     { 
      ((IDisposable)properties).Dispose(); 
     } 
    } 
} 

你的變量被設置在由如何通過工程性質。如果您希望能夠返回屬性,請不要將其封裝在使用塊中。

7

假設這是創建一次性對象的工廠方法的模式。但是,我仍然看到代碼分析抱怨這個,太:

 Wrapper tempWrapper = null; 
     Wrapper wrapper = null; 

     try 
     { 
      tempWrapper = new Wrapper(callback); 
      Initialize(tempWrapper); 

      wrapper = tempWrapper; 
      tempWrapper = null; 
     } 
     finally 
     { 
      if (tempWrapper != null) 
       tempWrapper.Dispose(); 
     } 

     return wrapper; 

這應該保證,如果初始化失敗,對象被妥善處理,但如果一切成功,一個未予處置實例從方法返回。

MSDN文章:CA2000: Dispose objects before losing scope

+0

這不是基本上等同於一個catch塊嗎?你爲什麼不寫'Wrapper x = null;嘗試{...} catch {if(x!= null)x.Dispose(); }'。意圖不僅100%更明顯,而且避免了不必要的臨時變量和手動清理。 – Juliet 2010-05-12 21:12:37

+0

我不反對。但是我最近剛看到了這個,我並不是因爲擔心在失敗時丟棄對象,而是因爲我試圖找到能夠消除CA2000警告的代碼模式,而不必通過屬性來禁用它。代碼分析過程會特別檢查是否由於執行規則的性質而將對象置於finally塊中。我認爲這個問題是關於CA2000的,而不是關於處理對象。 – Toby 2010-05-13 02:12:13

+1

@Juliet:catch語句缺少重新拋出,即使重新拋出語義也不一樣。除此之外,如果'try'塊包含調用某個可能導致異常的方法'blah',catch-and-rethrow將導致堆棧跟蹤顯示rethrow的行號,而不是調用' blah'('blah'中的堆棧跟蹤將是正確的,但是呼叫的行號不會)。 – supercat 2013-08-06 22:43:05

0

其他答案是正確的:只要您退出使用塊,您的對象就會被丟棄。使用block對於確保一個對象得到及時處理非常好,所以如果你不想依賴你的函數的用戶記住稍後處理對象,你可以嘗試這樣的事情:

public void UsingDataContext (Action<DataContext> action) 
{ 
    using (DataContext ctx = new DataContext()) 
    { 
     action(ctx) 
    } 
} 

這樣,你可以這樣說:

var user = GetNewUserInfo(); 
UsingDataContext(c => c.UserSet.Add(user));