System.Progress错误的调用顺序

时间:2015-09-30 06:42:20

标签: c# .net delegates

我正在尝试使用HttpClient显示下载进度。为此,我使用System.Progress<T>。代码如下所示:

long totalRead = 0L;
var buffer = new byte[1024];
bool isMoreToRead = true;
ulong total = (ulong)response.Content.Headers.ContentLength;

while (isMoreToRead)
{
    int read = await stream.ReadAsync(buffer, 0, buffer.Length);
    if (read == 0)
        isMoreToRead = false;
    else
    {
        var data = new byte[read];
        buffer.ToList().CopyTo(0, data, 0, read);
        totalRead += read;
        progress.Report((int) (totalRead*1d / total * 1d * 100) );
    }
}

假设订阅如下:

var progress = new Progress<int>();
progress.ProgressChanged += (sender, i) => Console.WriteLine(i);
client.Download(file, progress).Wait();

但结果是,进度顺序不一致,如下所示: 10,20,30,70,15,90,100,80。

这是默认委托的行为,还是有另一个原因?

1 个答案:

答案 0 :(得分:6)

Progress<T>.Report是异步的;我的意思是,Report方法在返回之前不会同步引发ProgressChanged事件。

Progress<T>类捕获SynchronizationContext并将ProgressChanged事件的调用发布到捕获的上下文。

在Winforms,Wpf等单线程上下文中使用时,您的代码将按预期工作。

在控制台应用程序中,不会有任何SynchronizationContext,因此Progress<T>会将调用发布到委托给ThreadPool的默认SynchronizationContext。 ThreadPool不保证任何订单,这是您没有看到同步结果的原因。

我相信您在控制台应用中测试此代码或其他类似的代码,否则您的代码没有任何问题。

如果您需要IProgress<T>的同步版本,则必须使用自己的版本。