Подтвердить что ты не робот

Доступ к закрытому закрытию в С#?

Я изучаю корпоративную библиотеку Microsoft (блок приложения данных) - образцы sln.

Они имеют пример данных чтения асинхронно (IAsync, хотя новый ver (6) также поддерживает async).

Но Resharper (или visual studio- nevermind) показывает мне: "Доступ к удаленному закрытию": (сначала я покажу изображение, так что оно будет более четким, тогда я вставлю код)

enter image description here

код:

/*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*/    }

Вопрос:

Почему это предупреждение? существует manualreset-checked-signal (который работает в цикле), который предотвращает предложение using, что означает - no dispose будет вызывать.

Итак, почему он кричит (предупреждение)?

4b9b3361

Ответ 1

Вы передаете doneWaitingEvent в лямбда, которая может выходить за пределы используемого блока. То есть существует риск, что Dispose будет вызван при выполнении лямбда.

Ответ 2

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

Вы можете смело игнорировать это предупреждение, вы можете заставить resharper подавить предупреждение, обернув строки специальными комментариями

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

Ответ 3

Причина, по которой вы видите предупреждения ReSharper, заключается в том, что механизм анализа потока кода ReSharper недостаточно силен, чтобы понять, что происходит: они предполагают, что ваш код может попасть в конец предложения using без doneWaitingEvent что невозможно из-за цикла while:

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

Цикл будет продолжать печатать строку "Waiting... " до тех пор, пока doneWaitingEvent.Set(); не будет вызван, чтобы ваш код не дошел до конца блока using. То же самое касается другого предупреждения.

Короче говоря, это предупреждение можно смело игнорировать. Добавьте комментарии ReSharper "игнорировать это предупреждение" и, возможно, файл с ними.