等待流的人口

时间:2013-12-29 04:53:21

标签: c# asynchronous stream resharper async-await

在我的MVC控制器中,我有一个动作将填充我稍后将使用的流:

[HttpPost]
public async Task<HttpResponseMessage> BuildFileContent(FileParameters fileParams)
{
    byte[] output;
    if (fileParams != null)
    {
        using (var stream = new MemoryStream())
        {
            await Task.Run(() => PopulateFile(fileParams, stream)); // Here i populate the stream
            stream.Flush();
            output = stream.ToArray();
        }
        var guid = Guid.NewGuid().ToString();
        FileContents.Add(guid, output); // just save the content for later use
        return this.Request.CreateResponse(HttpStatusCode.OK, new { Value = guid });
    }

    return this.Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid parameters");
}

我遇到了这个问题,因为ReSharper在access on disposed closure行发出警告:PopulateFile(fileParams, stream)并指出stream

我已经搜索了它的含义,它似乎警告我可以使用已经处理过的流。

我想等待流的填充,因为任务可能需要很长时间。

有没有办法让我可以在没有ReSharper发出此警告的情况下等待流的填充? 此外,我在stream子句中调用using,直到我调用flush或者using子句的最后一行被执行时才应该处理流?那么为什么ReSharper会警告访问一条被处理的流?

2 个答案:

答案 0 :(得分:5)

Resharper警告你,因为你正在lambda表达式中使用流,该表达式基本上可以在using范围内运行,而不仅仅在ObjectDisposedException范围内运行。
如果这是您的代码,您可以在任务结束之前处理该流,并且您手上会有Task task = null; using (var stream = new MemoryStream()) { task = Task.Run(() => PopulateFile(fileParams, stream)); // Here i populate the stream stream.Flush(); output = stream.ToArray(); } await task;

await

在您的情况下,您 using 该操作并仅在该操作完成后处理该流。所以基本上你是清楚的,但Resharper显然不知道。

要完全清除警告,您可以将await Task.Run(() => { using (var stream = new MemoryStream()) { PopulateFile(fileParams, stream); stream.Flush(); output = stream.ToArray(); } }); 范围放在任务中:

{{1}}

我建议你这样做。

答案 1 :(得分:1)

@ I3arnon的答案是完全正确的,但我想解决一个重点。

  

我想等待流的填充,因为任务可能需要很长时间。

这是一个崇高的目标,但受益于await完全取决于PopulateFile的实施,这可能不是一种异步方法,从它的调用方式来判断。无论何时你做await Task.Run(() => DoSomethingSynchronously())之类的事情,你在释放线程方面都没有任何收获。

我建议仔细查看PopulateFile,确定缓慢来自哪里,看看是否可以利用任何真正的异步API来处理Web accessfile I/O等等。如果你可以将PopulateFile重写为异步方法(即使用类似async Task PopulateFileAsync(...)的签名),利用这些API,您可以在等待长时间运行的操作时真正释放线程,并且可以直接等待它,而无需Task.Run

using (var stream = new MemoryStream())
{
    await PopulateFileAsync(fileParams, stream)); // Here i populate the stream
    stream.Flush();
    output = stream.ToArray();
}

作为奖励,上述代码不应引起R#的投诉。