2012-04-12 3 views
5

я получаю это сообщение для линии 84 и линий 85 (два, сложенные с использованием линий):правильный способ Dispose: объект не расположен вдоль всех путей исключения

CA2000: Microsoft.Reliability: В методе 'RavenDataAccess.GetRavenDatabase()', object '<> 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; 
    } 
} 
+0

проверить это, может быть, это тот самый материал, который у вас есть: http://stackoverflow.com/questions/3932131/how-to-get-rid-of-ca2000-warning-when-ownership-is-transferred – cookieMonster

+0

Это ссылка интересна. Я вызываю Add() on Shards, но не реализует ICollection. И поскольку Shards не мой код, я не могу его изменить. Это подпись Shards: public class Shards: List

+0

Хорошо, у вас есть шанс реализовать еще один? – cookieMonster

ответ

2

Вы должны обеспечить, чтобы все ваши вновь создаваемые одноразовые объекты располагались вдоль любого возможного пути исключения.См. Ниже:

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, похоже, есть проблема с инициализаторами свойств inline, но если вы их разблокируете, это должно сработать. Главное - убедиться, что независимо от того, где исключение выбрано в блоке try, все ваши новые объекты, которые могут быть удалены, очищаются. не

Устанавливая ссылки временные вам больше не нужно null (docStore1, docStore2 и tempShardedDocumentStore) как раз перед возвращением, вы можете проверить в конце концов заблокировать, чтобы увидеть, если они на самом деле были установлены null, если нет, то исключение произошло где-то, и вы можете избавиться от них до того, как выполнение оставит этот метод.

ПримечаниеdocStore1 и docStore2 временные ссылки, поскольку они добавляются к Shards коллекции.

+1

Это сработало! Вау, какая боль для чего-то вроде бы так проста. Спасибо, Джим! –

+0

@Bob - Попытка придерживаться CA может быть болью, но это по уважительной причине :-) Теперь, если бы только компилятор помог нам сделать все это автоматически, тогда нам не пришлось бы писать весь этот дополнительный код. – Jim

+0

docStores будут (вероятно) удалены дважды, если 'tempSharededDocumentStore.Initialize()' throws. Но это может быть хорошо. –

0

Учитывая, что CA2000: Dispose objects before losing scope документации государства (часть из него):

вложенности конструкторы, защищенные только один обработчик исключений. Например:

используя (StreamReader КН = новый StreamReader (новый FileStream ("C: \ myfile.txt", FileMode.Create))) {...}

вызывает CA2000 произойти из-за сбой в построении объекта StreamReader может привести к тому, что объект FileStream никогда не будет закрыт. .

и учитывая, что я не вижу в коде предоставил одноразовое выделение объекта другой, то DocumentStore себя, я бы предположил, что это ошибка компилятора.

1

Прежде всего, shards вы передаете new ShardedDocumentStore() содержит docStore1 и docStore2. Это, скорее всего, вызовет проблемы.

Кроме того, в выписке вы устанавливаете 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.

+0

Я пробовал это, и теперь я получаю три нарушения (две новые строки DocumentStore и новая строка ShardedDocumentStore). Я позволю вызывающему беспокоиться об утилизации, но вызывающий объект является статическим свойством в статическом классе: private static IDocumentStore _ravenDatabase = GetRavenDatabase(); –

+0

, а также почему компилятор отмечает это на строках 84,85? ... – Tigran

+0

Я обновил код для обработки исключений. Однако мне интересно, действительно ли компилятор может охватить все потоки. Я бы сказал, что API-интерфейс ravendb довольно дрянной, и, возможно, невозможно написать код, который не вызывает этого предупреждения. Возможно, вам нужно отключить предупреждение для этого кода? Что касается статического поля, я думаю, вам нужно найти другое решение для этого. –

1

Вот почему объект инициализаторы в результате, используя заявление в предупреждение 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 бросает excep , ваш DocumentStore не будет удален.

Существует несколько способов обхода пути, например, передача параметров в конструктор объекта, установка свойств внутри оператора using вместо использования инициализаторов объектов или использование блоков try/finally.

+0

Это хорошее представление о инициализаторе свойств, однако в этом примере Боб не должен использовать «использование» операторов на объектах, которые он планирует возвратить вызывающему. Используя «использование» операторов, его новые объекты будут удалены до того, как они будут возвращены и, таким образом, не будут использоваться вызывающим объектом этого метода. – Jim

+0

Yup, замечательная точка. Я полностью пропустил эту часть кода. –

+0

Спасибо за отзыв +1. Помог мне понять, почему это происходит в моем проекте. –