2012-04-12 21 views
5

consigo este mensaje para la línea 84 y la línea 85 (los dos, apilados utilizando líneas):forma correcta de Desechar: no objeto dispuesto a lo largo todos los caminos de excepción

CA2000: Microsoft.Reliability: En el método 'RavenDataAccess.GetRavenDatabase()', objeto '<> g_ initLocal9' no está eliminado en todas las rutas de excepción. Call System.IDisposable.Dispose en el objeto '<> g _initLocal9' antes de que todas las referencias estén fuera del alcance.

DocumentStore implementa IDisposable.

¿Por qué? ¿De qué otra forma puedo disponer los objetos de DocumentStore? Se crean en un bloque de uso y los desecho en mi bloque de captura. ¿Cómo debería ser esto arreglado?

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

compruébalo, tal vez es lo mismo que tienes: http://stackoverflow.com/questions/3932131/how-to-get-rid-of-ca2000-warning-when-ownership-is-transferred – cookieMonster

+0

Eso el enlace es interesante. Llamaré a Add() en Shards, pero no implementa ICollection. Y como Shards no es mi código, no puedo cambiarlo. Esta es la firma de Shards: shards de clase pública: List

+0

Ok, ¿tienes la oportunidad de implementar uno más? – cookieMonster

Respuesta

2

Debe asegurarse de disponer de todos sus Objetos desechables recién creados a lo largo de cualquier posible camino de excepción.Consulte a continuación:

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 parece tener un problema con los inicializadores de propiedades en línea, pero si los rompe, esto debería funcionar. La clave es asegurarse de que no importa dónde se lanza una excepción en el bloque try, todos los objetos nuevos que se pueden eliminar se limpian.

Al establecer las referencias temporales que ya no es necesario null (docStore1, docStore2 y tempShardedDocumentStore) justo antes de la devolución, se puede comprobar en el bloque finally para ver si, de hecho, se establecieron para null, si no, una la excepción se produjo en algún lugar y puede deshacerse de ellos antes de que la ejecución abandone este método.

NotadocStore1 y docStore2 son referencias temporales a medida que se agregan a la colección Shards.

+1

Esto funcionó! Wow, qué dolor por algo aparentemente tan simple. Gracias, Jim! –

+0

@Bob - Tratar de cumplir con CA puede ser una molestia, pero es por una buena razón :-) Ahora bien, si solo el compilador nos ayudara haciendo todo esto de forma automática, entonces no tendríamos que escribir todo este código adicional. – Jim

+0

Los docStores (probablemente) se eliminarán dos veces si 'tempSharededDocumentStore.Initialize()' lanza. Pero eso podría estar bien. –

0

Teniendo en cuenta que CA2000: Dispose objects before losing scope estados de documentación (parte de ella): constructores

de anidamiento que están protegidos por un solo gestor de excepciones. Por ejemplo:

usando (StreamReader sr = new StreamReader (nueva FileStream ("C: \ miarchivo.txt", FileMode.Create))) {...}

causa CA2000 a ocurrir porque una falla en la construcción del objeto StreamReader puede provocar que el objeto FileStream nunca se cierre .

y teniendo en cuenta que yo no veo en el código proporcionado ninguna asignación de objetos desechables otro entonces DocumentStore sí, yo supondría que este es un error del compilador.

1

En primer lugar, el shards que pasa a new ShardedDocumentStore() contiene docStore1 y docStore2 dispuestos. Esto muy probablemente cause problemas.

Además, en la declaración catch, deseche el docStores que podría estar dispuesto.

Por último, el ShardedDocumentStore que devolvió se desecha (al usarlo) cuando lo devuelve, lo que hace que sea inutilizable para la persona que llama.

Además, eché un vistazo rápido al ShardedDocumentStore (en GitHub) y diría que se encarga de la eliminación de su docStores. Es decir, no deberías manejarlo.

cambiar el código para esto:

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; 
    } 
} 

... y dejar que la persona que llama de GetRavenDatabase() disposición de asa de la IDocumentStore devuelto.

+0

Lo intenté y ahora recibo tres violaciones (las dos nuevas líneas de DocumentStore y la nueva línea de ShardedDocumentStore). Dejaría que la persona que llama se preocupe por la eliminación, pero la persona que llama es una propiedad estática en una clase estática: private static IDocumentStore _ravenDatabase = GetRavenDatabase(); –

+0

y también por qué el compilador lo anota en las líneas 84,85? ... – Tigran

+0

Actualicé el código para manejar excepciones. Sin embargo, me pregunto si el compilador realmente puede cubrir todos los flujos. Diría que la API de ravendb es bastante mala y que podría ser imposible escribir código que no genere esta advertencia. ¿Quizás necesites inhabilitar la advertencia para este código? Y con respecto al campo estático, creo que debes encontrar una solución diferente para eso. –

1

He aquí por qué inicializadores de objeto en consecuencia, la cuenta utilizando en la advertencia CA:

Su código que se parece a esto:

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

... essentialy se convierte en esto, debido a la forma inicializadores de objeto de trabajo :

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

así como se puede ver, la inicialización de la DocumentStore ahora sucede fuera del bloque usando {}, por lo que si la línea que establece temp.Url lanza una excep ción, su DocumentStore no será eliminada.

Hay una serie de soluciones, como pasar los parámetros en el constructor del objeto, establecer las propiedades dentro de la instrucción using en lugar de usar los inicializadores de objetos o usar los bloques try/finally.

+0

Esta es una buena idea en el inicializador de propiedades; sin embargo, en este ejemplo, Bob no debe usar declaraciones "usando" sobre objetos que planea devolver a la persona que llama. Al usar las declaraciones de "uso", sus nuevos objetos serán eliminados antes de ser devueltos y, por lo tanto, no podrán ser utilizados por el que llama de este método. – Jim

+0

Sí, gran punto ... Eché de menos esa parte del código. –

+0

Gracias por el consejo +1. Me ayudó a entender por qué estaba sucediendo en mi proyecto. –

Cuestiones relacionadas