[英]Proper Way to Dispose: object not disposed along all exception paths
我收到第84行和第85行的消息(兩個, 使用行堆疊):
CA2000:Microsoft.Reliability:在方法'RavenDataAccess.GetRavenDatabase()'中,對象'<> g_ initLocal9'未沿所有異常路徑放置。 在對對象'<> g _initLocal9'的所有引用都超出范圍之前, 調用System.IDisposable.Dispose 。
DocumentStore實現了IDisposable。
為什么? 我還能如何處置DocumentStore對象? 它們是在一個使用塊中創建的,我將它們放在我的catch塊中。 該如何修復?
private static IDocumentStore GetRavenDatabase()
{
Shards shards = new Shards();
try
{
using (DocumentStore docStore1 = new DocumentStore { Url = ConfigurationManager.AppSettings["RavenShard1"] }) // Line 84
using (DocumentStore docStore2 = new DocumentStore { Url = ConfigurationManager.AppSettings["RavenShard2"] }) // Line 85
{
shards.Add(docStore1);
shards.Add(docStore2);
}
using (ShardedDocumentStore documentStore = new ShardedDocumentStore(new ShardStrategy(), shards))
{
documentStore.Initialize();
IndexCreation.CreateIndexes(typeof(RavenDataAccess).Assembly, documentStore);
return documentStore;
}
}
catch
{
shards.ForEach(docStore => docStore.Dispose());
throw;
}
}
您必須確保沿任何可能的異常路徑處置所有新創建的Disposable對象。 見下文:
private static IDocumentStore GetRavenDatabase()
{
Shards shards = new Shards();
DocumentStore docStore1 = null;
DocumentStore docStore2 = null;
ShardedDocumentStore shardedDocumentStore = null;
ShardedDocumentStore tempShardedDocumentStore = null;
try
{
docStore1 = new DocumentStore();
docStore1.Url = ConfigurationManager.AppSettings["RavenShard1"];
docStore2 = new DocumentStore();
docStore2.Url = ConfigurationManager.AppSettings["RavenShard2"];
shards.Add(docStore1);
shards.Add(docStore2);
tempShardedDocumentStore = new ShardedDocumentStore(new ShardStrategy(), shards);
tempShardedDocumentStore.Initialize();
IndexCreation.CreateIndexes(typeof(RavenDataAccess).Assembly, tempShardedDocumentStore);
docStore1 = null;
docStore2 = null;
shardedDocumentStore = tempShardedDocumentStore;
tempShardedDocumentStore = null;
return shardedDocumentStore;
}
finally
{
if (tempShardedDocumentStore != null) { tempShardedDocumentStore.Dispose(); }
if (docStore1 != null) { docStore1.Dispose(); }
if (docStore2 != null) { docStore2.Dispose(); }
}
}
CA似乎有內聯屬性初始值設定項的問題,但是如果你將它們分解出來,這應該可行。 關鍵是要確保無論try塊中拋出異常的位置,都可以清除所有可以處置的新對象。
通過設置臨時引用,您不再需要在返回之前使用null
( docStore1
, docStore2
和tempShardedDocumentStore
),您可以檢查finally塊以查看它們實際上是否設置為null
,如果沒有,則在某處發生異常並且您可以在執行離開此方法之前處置它們。
注意 docStore1
和docStore2
是臨時引用,因為它們被添加到Shards
集合中。
首先,該shards
傳遞到new ShardedDocumentStore()
包含布置docStore1
和docStore2
。 這很可能會導致問題。
此外,在catch語句中,您將docStores
可能已經處置的docStores
。
最后,當您返回時,您返回的ShardedDocumentStore
正在處理(通過使用),可能使其無法用於調用者。
另外,我快速瀏覽了ShardedDocumentStore
(在GitHub上),我會說它會處理它的docStores
。 也就是說,你不應該處理它。
將您的代碼更改為:
private static IDocumentStore GetRavenDatabase()
{
ShardedDocumentStore documentStore = null;
var docStore1 = null;
var docStore2 = null;
try
{
Shards shards = new Shards();
docStore1 = new DocumentStore { Url = ConfigurationManager.AppSettings["RavenShard1"] };
shards.Add(docStore1);
docStore2 = new DocumentStore { Url = ConfigurationManager.AppSettings["RavenShard2"] };
shards.Add(docStore2);
documentStore = new ShardedDocumentStore(new ShardStrategy(), shards);
documentStore.Initialize();
IndexCreation.CreateIndexes(typeof(RavenDataAccess).Assembly, documentStore);
return documentStore;
}
catch
{
if (documentStore != null)
{
documentStore.Dispose();
}
else
{
if (docStore2 != null) docStore2.Dispose();
if (docStore1 != null) docStore1.Dispose();
}
throw;
}
}
...讓GetRavenDatabase()
的調用者處理返回的IDocumentStore
。
這就是為什么using語句中的對象初始化器導致CA警告的原因:
您的代碼如下所示:
using (DocumentStore docStore2 = new DocumentStore { Url = ConfigurationManager.AppSettings["RavenShard2"] }) // Line 85
{
...
}
...由於對象初始化程序的工作方式,essentialy成為了這個:
DocumentStore foo = new DocumentStore;
foo.Url = ConfigurationManager.AppSettings["RavenShard2"];
using(DocumentStore docStore2 = foo)
{
...
}
正如您所看到的,DocumentStore的初始化現在發生在using {}塊之外,因此如果設置temp.Url的行引發異常,則不會釋放DocumentStore。
有許多變通方法,例如將參數傳遞給對象的構造函數,在using語句中設置屬性而不是使用對象初始化器,或使用try / finally塊。
考慮到CA2000:在丟失范圍文檔狀態之前處置對象 (部分來自它):
嵌套僅由一個異常處理程序保護的構造函數。 例如:
using(StreamReader sr = new StreamReader(new FileStream (“C:\\ myfile.txt”,FileMode.Create))){...}
導致CA2000發生,因為構造StreamReader對象失敗可能導致FileStream對象永遠不會被關閉。
並且考慮到我沒有在代碼中看到提供除DocumentStore
本身之外的任何一次性對象分配,我認為這是編譯器的錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.