Sto*_*tip 2 c# wpf task-parallel-library async-await
至少当我在我的代码中实现它时,我不得不修改StartNew Task以获得相同的行为.在我的视图中有一个开始按钮.它的IsEnabled属性绑定到View Model中的Boolean.在不添加await task.ContinueWith(_ => true);和return true;移出try块的情况下,PopulateListStartNew任务不会等待,因此按钮保持启用状态.我更喜欢使用,Task.Factory.StartNew因为传递TaskScheduler会产生更易读的代码(没有Dispatcher混乱).记录是一个ObservableCollection.
我认为Task.Run基本上是一个快捷方式(每个Task.Run vs Task.Factory.StartNew.无论如何,我想更好地理解行为上的差异,并且肯定会感谢任何有关使我的示例代码更好的建议.
public async Task<bool> PopulateListTaskRun(CancellationToken cancellationToken)
{
try
{
await Task.Run(async () =>
{
// Clear the records out first, if any
Application.Current.Dispatcher.InvokeAsync(() => Records.Clear());
for (var i = 0; i < 10; i++)
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
// Resharper says do this to avoid "Access to modified closure"
var i1 = i;
Application.Current.Dispatcher.InvokeAsync(() =>
{
Records.Add(new Model
{
Name = NamesList[i1],
Number = i1
});
Status = "cur: " +
i1.ToString(
CultureInfo.InvariantCulture);
});
// Artificial delay so we can see what's going on
await Task.Delay(200);
}
Records[0].Name = "Yes!";
}, cancellationToken);
return true;
}
catch (Exception)
{
return false;
}
}
public async Task<bool> PopulateListStartNew(CancellationToken cancellationToken, TaskScheduler taskScheduler)
{
try
{
var task = await Task.Factory.StartNew(async () =>
{
// Clear the records out first, if any
Records.Clear();
for (var i = 0; i < 10; i++)
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
Records.Add(new Model
{
Name = NamesList[i],
Number = i
});
Status = "cur: " +
i.ToString(
CultureInfo.InvariantCulture);
// Artificial delay so we can see what's going on
await Task.Delay(200);
}
Records[0].Name = "Yes!";
}, cancellationToken, TaskCreationOptions.None, taskScheduler);
// Had to add this
await task.ContinueWith(_ => true);
}
catch (Exception)
{
return false;
}
// Had to move this out of try block
return true;
}
Run Code Online (Sandbox Code Playgroud)
您在问题中发布的链接有答案:Task.Run理解和解包async Task代表,而StartNew返回Task<Task>代替,您必须通过调用Unwrap或执行双重解包来解开自己await.
但是,我建议您完全重写代码如下.笔记:
Dispatcher.使用正确编写的async代码不应该需要它.像这样:
public async Task<bool> PopulateListTaskRunAsync(CancellationToken cancellationToken)
{
try
{
// Clear the records out first, if any
Records.Clear();
for (var i = 0; i < 10; i++)
{
cancellationToken.ThrowIfCancellationRequested();
Records.Add(new Model
{
Name = NamesList[i],
Number = i
});
Status = "cur: " + i.ToString(CultureInfo.InvariantCulture);
// Artificial delay so we can see what's going on
await Task.Delay(200);
}
Records[0].Name = "Yes!";
return true;
}
catch (Exception)
{
return false;
}
}
Run Code Online (Sandbox Code Playgroud)