web-dev-qa-db-fra.com

Accès à la fermeture éliminée en C #?

J'étudie la bibliothèque d'entreprise Microsoft (bloc d'application de données) - Les exemples sln.

Ils ont un échantillon de lecture de données asynchrone (IAsync, bien que le nouveau ver (6) supporte également async).

Mais Resharper ( ou visual studio- nevermind ) me montre: "Accès à la fermeture éliminée": (d'abord je montrerai l'image, donc ce sera plus clair , je vais coller le code)

enter image description here

code:

/*1*/    [Description("Execute a command that retrieves data asynchronously")]
/*2*/    static void ReadDataAsynchronously()
/*3*/    {
/*4*/        if (!SupportsAsync(asyncDB)) return;
/*5*/   
/*6*/        using(var doneWaitingEvent = new ManualResetEvent(false))
/*7*/        using(var readCompleteEvent = new ManualResetEvent(false))
/*8*/        {
/*9*/            try
/*10*/            {
/*11*/                // Create command to execute stored procedure and add parameters
/*12*/                DbCommand cmd = asyncDB.GetStoredProcCommand("ListOrdersSlowly");
/*13*/                asyncDB.AddInParameter(cmd, "state", DbType.String, "Colorado");
/*14*/                asyncDB.AddInParameter(cmd, "status", DbType.String, "DRAFT");
/*15*/                // Execute the query asynchronously specifying the command and the
/*16*/                // expression to execute when the data access process completes.
/*17*/                asyncDB.BeginExecuteReader(cmd,
/*18*/                    asyncResult = >
/*19*/                    {
/*20*/                        // Lambda expression executed when the data access completes.
/*21*/                        doneWaitingEvent.Set();
/*22*/                        try
/*23*/                        {
/*24*/                            using(IDataReader reader = asyncDB.EndExecuteReader(asyncResult))
/*25*/                            {
/*26*/                                Console.WriteLine();
/*27*/                                Console.WriteLine();
/*28*/                                DisplayRowValues(reader);
/*29*/                            }
/*30*/                        }
/*31*/                        catch (Exception ex)
/*32*/                        {
/*33*/                            Console.WriteLine("Error after data access completed: {0}", ex.Message);
/*34*/                        }
/*35*/                        finally
/*36*/                        {
/*37*/                            readCompleteEvent.Set();
/*38*/                        }
/*39*/                    }, null);
/*40*/   
/*41*/                // Display waiting messages to indicate executing asynchronouly
/*42*/                while (!doneWaitingEvent.WaitOne(1000))
/*43*/                {
/*44*/                    Console.Write("Waiting... ");
/*45*/                }
/*46*/   
/*47*/                // Allow async thread to write results before displaying "continue" Prompt
/*48*/                readCompleteEvent.WaitOne();
/*49*/            }
/*50*/            catch (Exception ex)
/*51*/            {
/*52*/                Console.WriteLine("Error while starting data access: {0}", ex.Message);
/*53*/            }
/*54*/        }
/*55*/    }

Question:

Pourquoi donne-t-il cet avertissement? Il y a un manualreset-checked-signal (qui s'exécute en boucle) qui empêche la clause using à atteindre - ce qui signifie - aucun dispose n'appellera.

Alors pourquoi crie-t-il (avertissement)?

59
Royi Namir

Vous passez doneWaitingEvent à un lambda qui peut s'étendre au-delà de la portée du bloc using. C'est à dire. il y a un risque que Dispose ait été appelé lors de l'exécution de lambda.

66
Brian Rasmussen

Il crie un avertissement car le moteur n'est pas assez intelligent pour comprendre que le bloc using ne sera jamais quitté avant la fin du code délégué. C'est pourquoi il s'agit d'un avertissement et non d'une erreur.

Vous pouvez ignorer cet avertissement en toute sécurité, vous pouvez demander à resharper de supprimer l'avertissement en encapsulant les lignes avec des commentaires spéciaux.

asyncDB.BeginExecuteReader(cmd, asyncResult =>
{
    // Lambda expression executed when the data access completes.
    // ReSharper disable AccessToDisposedClosure
    doneWaitingEvent.Set();
    // ReSharper restore AccessToDisposedClosure
    try
    {
        using (IDataReader reader = asyncDB.EndExecuteReader(asyncResult))
        {
            Console.WriteLine();
            Console.WriteLine();
            DisplayRowValues(reader);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error after data access completed: {0}", ex.Message);
    }
    finally
    {
        // ReSharper disable AccessToDisposedClosure
        readCompleteEvent.Set();
        // ReSharper restore AccessToDisposedClosure
    }
}, null);
56
Scott Chamberlain

La raison pour laquelle vous voyez les avertissements de ReSharper est que le moteur d'analyse de flux de code de ReSharper n'est pas assez puissant pour voir ce qui se passe: ils supposent que votre code pourrait atteindre la fin de la clause using sans doneWaitingEvent étant défini, ce qui n'est pas possible en raison d'une boucle while:

while (!doneWaitingEvent.WaitOne(1000)) {
    Console.Write("Waiting... ");
}

La boucle continuera à imprimer la ligne "Waiting... " Jusqu'à ce que doneWaitingEvent.Set(); soit appelée, empêchant votre code d'atteindre la fin du bloc using. Il en va de même pour l'autre avertissement.

Pour faire court, cet avertissement peut être ignoré en toute sécurité. Ajoutez les commentaires "Ignorer cet avertissement" de ReSharper et, éventuellement, envoyez un rapport de bogue avec eux.

5
dasblinkenlight