简体   繁体   English

访问C#中已处理的闭包?

[英]Access to disposed closure in C#?

I'm investigating Microsoft enterprise library (data application block) -- The samples sln. 我正在研究Microsoft企业库(数据应用程序块)-样本sln。

They have a sample of reading data asynchronously ( IAsync , although the new ver (6) also support async ). 他们有一个异步读取数据的示例( IAsync ,尽管新版本(6)也支持async )。

But Resharper( or visual studio- nevermind ) shows me : "Access to disposed closure" : (first i will show the image , so it will be clearer , then i'll paste the code ) 但是Resharper( 或visual studio- nevermind )向我显示:“访问已设置的封闭” :(首先,我将显示图像,这样会更清晰,然后粘贴代码)

在此处输入图片说明

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 : 题 :

Why is it giving this warning ? 为什么会发出此警告? there is a manualreset-checked-signal (which runs in a loop) which prevents the using clause to be reached - which means - no dispose will call . 有一个manualreset-checked-signal (循环运行),该信号防止到达using子句-这意味着-不会调用dispose

So why does it yell (warning) ? 那么为什么会大喊(警告)?

You pass doneWaitingEvent to a lambda that may extend beyond the scope of the using block. 您将doneWaitingEvent传递给一个lambda,该lambda可能会超出using块的范围。 Ie there's a risk that Dispose will have been called when the lambda executes. 也就是说,有可能在执行lambda时调用Dispose

It yells warning because the engine is not smart enough to figure out that the using block will never be exited before the delegate code completes. 之所以大声警告,是因为引擎不够聪明,无法确定在委托代码完成之前永远不会退出using块。 That is why this is a warning not a error. 这就是为什么这是警告而不是错误。

You can safely ignore this warning, you can have resharper suppress the warning by wrapping the lines with special comments 您可以放心地忽略此警告,可以通过用特殊注释将行换行来使harshaper抑制该警告

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

The reason you see ReSharper's warnings is that ReSharper's code flow analysis engine is not strong enough to see what is going on: they assume that your code could get to the end of the using clause without doneWaitingEvent being set, which is not possible due to a while loop: 之所以会看到ReSharper的警告,是因为ReSharper的代码流分析引擎不够强大,无法了解正在发生的情况:他们认为您的代码可能在未设置doneWaitingEvent情况下doneWaitingEventusing子句的结尾,由于while循环:

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

The loop will keep printing the "Waiting... " line until doneWaitingEvent.Set(); 循环将继续打印"Waiting... "行,直到doneWaitingEvent.Set(); gets called, preventing your code from reaching the end of the using block. 被调用,以防止您的代码到达using块的末尾。 Same goes for the other warning. 其他警告也一样。

Long story short, this warning can be safely ignored. 长话短说,可以安全地忽略此警告。 Add ReSharper's "ignore this warning" comments, and optionally file a bug report with them. 添加ReSharper的“忽略此警告”注释,并可以选择向其提交错误报告。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM