c# - Progress<T> 与 Action<T> 有何不同? (C#)

标签 c# generics delegates progress

我一直在使用 Progress<T>并想知道是否可以将其替换为 Action<T> .

在下面的代码中,使用它们中的每一个来报告进度,即 ReportWithProgress()ReportWithAction() ,对我没有任何明显的影响。如何progressBar1增加了,字符串在输出窗口上的写法,他们看起来是一样的。

// WinForm application with progressBar1

private void HeavyIO()
{
    Thread.Sleep(20); // assume heavy IO
}

private async Task ReportWithProgress()
{
    IProgress<int> p = new Progress<int>(i => progressBar1.Value = i);

    for (int i = 0; i <= 100; i++)
    {
        await Task.Run(() => HeavyIO()); 
        Console.WriteLine("Progress : " + i);
        p.Report(i);
    }
}

private async Task ReportWithAction()
{
    var a = new Action<int>(i => progressBar1.Value = i);

    for (int i = 0; i <= 100; i++)
    {
        await Task.Run(() => HeavyIO());
        Console.WriteLine("Action : " + i);
        a(i);
    }
} 

但是Progress<T>不能是重新发明轮子。应该有它被实现的原因。谷歌搜索“c# Progress vs Action”并没有给我太多帮助。 Progress 与 Action 有何不同?

最佳答案

从不同的线程调用 progressBar1.Value = i 会导致可怕的 "cross-thread operation not valid"异常(exception)。另一方面,Progress 类将事件分派(dispatch)给 synchronization context。拍摄于施工时刻:

// simplified code, check reference source for actual code

void IProgress<T>.Report(T value)
{
    // post the processing to the captured sync context
    m_synchronizationContext.Post(InvokeHandlers, value);
}

private void InvokeHandlers(object state)
{
    // invoke the handler passed through the constructor
    m_handler?.Invoke((T)state);

    // invoke the ProgressChanged event handler
    ProgressChanged?.Invoke(this, (T)state);
}

这确保了对进度条、标签和其他 UI 元素的所有更新都在(一个且唯一的)GUI 线程上完成。

因此,只有在后台线程的 外部 实例化 Progress 类才有意义,在 UI 线程上调用的方法内:

void Button_Click(object sender, EventArgs e)
{
    // since this is a UI event, instantiating the Progress class
    // here will capture the UI thread context
    var progress = new Progress<int>(i => progressBar1.Value = i);

    // pass this instance to the background task
    Task.Run(() => ReportWithProgress(progress));
}

async Task ReportWithProgress(IProgress<int> p)
{
    for (int i = 0; i <= 100; i++)
    {
        await Task.Run(() => HeavyIO());
        Console.WriteLine("Progress : " + i);
        p.Report(i);
    }
}

关于c# - Progress<T> 与 Action<T> 有何不同? (C#),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48625152/

相关文章:

c# - 注册 CancellationToken 回调调用顺序

c# - 将 winforms 控件的属性绑定(bind)到多个对象属性

c# - 我怎样才能缩短这个代码片段?

generics - 在 Nim 中使用泛型转换类型时出现 ObjectConversionError

c# - 从基类实例化派生类的通用工厂方法

在 C 中检查对 _Generic() 选择的支持

c# - 在 C# 中使用泛型参数调用委托(delegate)

c# - EnumerateFiles 以避免缓存

ios - 代理的属性 "assign"和 "retain"

c# - 将 lambda 表达式附加到 C# 程序的 main 方法会产生什么结果?