Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在一项任务中,为什么IProgress<;T>;在UI线程中正确执行,但不是操作<;T>;?_C#_Multithreading_Task_Dispatcher - Fatal编程技术网

C# 在一项任务中,为什么IProgress<;T>;在UI线程中正确执行,但不是操作<;T>;?

C# 在一项任务中,为什么IProgress<;T>;在UI线程中正确执行,但不是操作<;T>;?,c#,multithreading,task,dispatcher,C#,Multithreading,Task,Dispatcher,关于以下代码: Task UpdateMedias<TProperty>(Expression<Func<Media, TProperty>> property, Func<Media, TProperty> func) { var medias = GetSelectedMedias().ToList(); IProgress<double> progress = new Progress<double>(

关于以下代码:

Task UpdateMedias<TProperty>(Expression<Func<Media, TProperty>> property, Func<Media, TProperty> func)
{
    var medias = GetSelectedMedias().ToList();
    IProgress<double> progress = new Progress<double>(d => barQueueProgress.EditValue = d);
    Action<Media, Expression<Func<Media, TProperty>>, Func<Media, TProperty>> action =
        (media, expression, arg3) => UpdateMedia(media, expression, arg3);
    Task task = Task.Run(() =>
    {
        var i = 0;
        foreach (var media in medias)
        {
            progress.Report(1.0d / medias.Count * ++i);
            action(media, property, func);
        }
    });
    Task with = task.ContinueWith(s =>
    {
        progress.Report(0.0d);
        GridControl1.RefreshData();
    });
    return with;
}
任务更新数据(表达式属性,Func Func)
{
var medias=GetSelectedMedias().ToList();
IProgress progress=新进度(d=>barQueueProgress.EditValue=d);
行动=
(媒体,表达式,arg3)=>UpdateMedia(媒体,表达式,arg3);
任务=任务。运行(()=>
{
var i=0;
foreach(媒体中的var媒体)
{
进度报告(1.0d/medias.Count*++i);
行动(媒体、财产、职能);
}
});
任务与=任务。继续与(s=>
{
进度报告(0.0d);
GridControl1.RefreshData();
});
返回与;
}
如果我没有将
操作
包含在
Dispatcher.BeginInvoke
中,它将向调用线程抱怨无法访问此对象,因为它是另一个线程拥有的。而对于
进度
则无需这样做


为什么
IProgress
不需要调度程序就可以工作。BeginInvoke?

因为内部
进度
存储了对
同步上下文中的内容的引用。当前的
在构建时,在报告进度时会触发该上下文中的事件

它是专门为从非UI线程更新UI而设计的。如果它不这样做,就没有那么多理由使用它,也不难做到

下面是我使用的
Progress
pre.NET4.5的实现。它与.NET实现不同,但它会让您对正在发生的事情有一个非常好的了解:

public interface IProgress<T>
{
    void Report(T data);
}

public class Progress<T> : IProgress<T>
{
    SynchronizationContext context;
    public Progress()
    {
        context = SynchronizationContext.Current
            ?? new SynchronizationContext();
    }

    public Progress(Action<T> action)
        : this()
    {
        ProgressReported += action;
    }

    public event Action<T> ProgressReported;

    void IProgress<T>.Report(T data)
    {
        var action = ProgressReported;
        if (action != null)
        {
            context.Post(arg => action((T)arg), data);
        }
    }
}
公共接口程序
{
无效报告(T数据);
}
公开课进展:IProgress
{
同步上下文;
公共进步()
{
context=SynchronizationContext.Current
??新的SynchronizationContext();
}
公共进步(行动)
:此()
{
进度报告+=行动;
}
公共事件行动报告;
无效进程报告(T数据)
{
var行动=报告的进展;
如果(操作!=null)
{
Post(arg=>action((T)arg),数据);
}
}
}

这个答案帮助我理解了为什么调用
progress.Report
是有效的,即使它是在等待的
任务之后执行的,该任务配置为
ConfigureAwait(false)
。此外,文档中的注释确实确认了在构建
进度
时捕获
同步上下文
实例。