it-swarm.asia

الوصول إلى إغلاق التخلص في C #؟

أقوم بالتحقيق في مكتبة مؤسسة Microsoft (كتلة تطبيق البيانات) - العينات sln.

لديهم عينة من قراءة البيانات بشكل غير متزامن (IAsync ، على الرغم من أن الإصدار الجديد (6) يدعم أيضًا async).

لكن Resharper ( أو الاستوديو المرئي ) يوضح لي: "الوصول إلى الإغلاق الذي تم التخلص منه": (أولاً سأعرض الصورة ، لذلك ستكون أكثر وضوحًا ، ثم سألصق الرمز )

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 التي سيتم الوصول إليها - مما يعني - لن يتم استدعاء dispose.

فلماذا يصيح (تحذير)؟

58
Royi Namir

يمكنك تمرير doneWaitingEvent إلى lambda التي قد تمتد خارج نطاق كتلة الاستخدام. أي. هناك خطر من أنه قد يتم استدعاء Dispose عند تنفيذ lambda.

64
Brian Rasmussen

يصيح هذا التحذير لأن المحرك غير ذكي بما فيه الكفاية لمعرفة أنه لن يتم إنهاء كتلة الاستخدام قبل اكتمال كود التفويض. هذا هو السبب في هذا تحذير وليس خطأ.

يمكنك تجاهل هذا التحذير بأمان ، يمكنك إعادة ضبط التحذير عن طريق التفاف الأسطر بتعليقات خاصة

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);
53
Scott Chamberlain

السبب في ظهور تحذيرات ReSharper هو أن محرك تحليل تدفق الكود في ReSharper ليس قويًا بما يكفي لمعرفة ما يحدث: يفترضون أن الشفرة قد تصل إلى نهاية جملة using دون تعيين doneWaitingEvent ، وهذا غير ممكن بسبب وجود حلقة while:

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

ستستمر الحلقة في طباعة سطر "Waiting... " حتى يتم استدعاء doneWaitingEvent.Set(); ، مما يمنع رمزك من الوصول إلى نهاية كتلة using. الشيء نفسه ينطبق على التحذير الآخر.

قصة قصيرة طويلة ، يمكن تجاهل هذا التحذير بأمان. أضف تعليقات "تجاهل هذا التحذير" في ReSharper ، وقم بشكل اختياري بتقديم تقرير عن الأخطاء معهم.

5
dasblinkenlight