65

我正在调查 Microsoft 企业库(数据应用程序块)——示例 sln。

他们有一个异步读取数据的示例(IAsync尽管新版本(6)也支持async)。

但是 Resharper(或 Visual Studio- Nevermind)向我展示了:“访问已处置的闭包”:(首先我将显示图像,这样会更清晰,然后我将粘贴代码)

在此处输入图像描述

代码 :

/*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子句 - 这意味着 - nodispose将调用 .

那么它为什么会大喊(警告)呢?

4

3 回答 3

73

您传递doneWaitingEvent给可能超出 using 块范围的 lambda。即Dispose当 lambda 执行时存在被调用的风险。

于 2013-07-12T17:19:21.587 回答
59

它发出警告是因为引擎不够聪明,无法确定在委托代码完成之前永远不会退出 using 块。这就是为什么这是警告而不是错误的原因。

您可以放心地忽略此警告,您可以通过使用特殊注释包装行来让 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);
于 2013-07-12T17:20:39.087 回答
5

您看到 ReSharper 警告的原因是 ReSharper 的代码流分析引擎不够强大,无法查看发生了什么:他们假设您的代码可以在using没有设置的情况下到达子句的末尾,由于循环doneWaitingEvent,这是不可能的:while

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

循环将继续打印该"Waiting... "行直到doneWaitingEvent.Set();被调用,从而防止您的代码到达using块的末尾。另一个警告也是如此。

长话短说,可以放心地忽略此警告。添加 ReSharper 的“忽略此警告”注释,并可选择与它们一起提交错误报告。

于 2013-07-12T17:20:51.447 回答