5

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

CA2000:Microsoft.Reliability:在方法“RavenDataAccess.GetRavenDatabase()”中,对象“<> g_initLocal9”并未沿所有异常路径进行处理。在对对象“<>g _initLocal9”的所有引用超出范围之前调用 System.IDisposable.Dispose。

DocumentStore 实现 IDisposable。

为什么?我还能如何处理 DocumentStore 对象?它们是在 using 块中创建的,我将它们放在我的 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;
    }
}
4

4 回答 4

2

您必须确保沿任何可能的异常路径处理所有新创建的 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 块中哪里抛出异常,所有可以释放的新对象都被清理干净。

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

注意 docStore1docStore2是临时参考,因为它们被添加到Shards集合中。

于 2012-04-12T15:33:02.663 回答
1

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

此外,在 catch 语句中,您处置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.

于 2012-04-12T14:15:26.577 回答
1

这就是为什么 using 语句中的对象初始值设定项会导致 CA 警告的原因:

您的代码如下所示:

using (DocumentStore docStore2 = new DocumentStore { Url = ConfigurationManager.AppSettings["RavenShard2"] })  // Line 85
{
   ...
}

...由于对象初始化程序的工作方式,本质上变成了这样:

DocumentStore foo = new DocumentStore;
foo.Url = ConfigurationManager.AppSettings["RavenShard2"];
using(DocumentStore docStore2 = foo)
{
   ...
}

如您所见,DocumentStore 的初始化现在发生在 using{} 块之外,因此如果设置 temp.Url 的行抛出异常,您的 DocumentStore 将不会被释放。

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

于 2012-04-12T16:15:26.320 回答
0

考虑到CA2000: Dispose objects before lost scope文档状态(部分):

仅受一个异常处理程序保护的嵌套构造函数。例如:

使用 (StreamReader sr = new StreamReader(new FileStream ("C:\myfile.txt", FileMode.Create))) { ... }

导致 CA2000 发生,因为 StreamReader 对象的构造失败可能导致FileStream对象永远不会关闭。

并且考虑到我在代码中没有看到提供任何一次性对象分配而不是DocumentStore它本身,我认为这是编译器的错误。

于 2012-04-12T14:09:19.627 回答