正确的处理方法:对象不会沿着所有异常路径进行处理

我收到了第84行和第85行的这条消息(这两条,使用行堆积):

CA2000:Microsoft.Reliability:在方法'RavenDataAccess.GetRavenDatabase()'中,对象'<> g_initLocal9'不会沿着所有异常路径放置。 调用System.IDisposable.Dispose对象'<> g_initLocal9'之前,所有对它的引用超出范围。

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块中抛出异常,所有可以处理的新对象都将被清除。

通过设置临时引用,您不再需要在返回之前为nulldocStore1docStore2tempShardedDocumentStore ),您可以检查finally块以查看它们实际上是否设置为null ,如果不是,则会在某处发生异常,您可以在执行离开此方法之前处置它们。

注意 docStore1docStore2是添加到Shards集合中的临时引用。


首先,您传入new ShardedDocumentStore()shards包含处置的docStore1docStore2 。 这很可能会导致问题。

另外,在catch语句中,您可以处理可能已被处置的docStores

最后,您返回的ShardedDocumentStore将在您返回时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的初始化现在发生在使用{}块之外,因此如果设置temp.Url的行引发异常,则不会丢弃DocumentStore。

有许多解决方法,比如将参数传递给对象的构造函数,在using语句中设置属性,而不是使用对象初始值设定项,或使用try / finally块。

链接地址: http://www.djcxy.com/p/63015.html

上一篇: Proper Way to Dispose: object not disposed along all exception paths

下一篇: friendly way to dispose of objects