【发布时间】:2015-09-30 10:30:37
【问题描述】:
UI 可以使用IProgress 或BackgroundWorker.ReportProgress 从异步任务传递信息:
class Approach1 : UserControl
{
enum Stage { INIT, STATUS, DATA, TIME, ... }
struct ProgressObject
{
int StatusCode;
int SecondsRemaining;
IList<int> Data;
Stage CurrentStage;
}
TextBox Status;
async Task DoWork1(IProgress<ProgressObject> progress)
{
await Task.Run( () =>
{
progress.Report(new ProgressObject(0, 0, null, Stage.INIT));
int code = DoSomething();
progress.Report(new ProgressObject(code, 0, null, Stage.STATUS));
IList<int> Data = ...;
progress.Report(new ProgressObject(0, 0, Data, Stage.DATA));
int Seconds = ...;
progress.Report(new ProgressObject(0, time, null, Stage.TIME));
});
}
void ReportProgress(ProgressObject progress)
{
switch (progress.CurrentStage)
{
case Stage.CODE:
Status.Text = DecodeStatus(progress.StatusCode);
break;
// And so forth...
}
}
async void Caller1(object sender, EventArgs e)
{
var progress = new Progress<ProgressObject>(ReportProgress);
await DoWork2(progress);
}
}
但是,这也可以通过将委托传递给 UI 对象的 BeginInvoke 方法来完成(如果我们想阻止,则为 Invoke):
class Approach2 : UserControl
{
Textbox Status;
int StatusCode
{
set
{
BeginInvoke(new Action( () => Status.Text = DecodeStatus(value));
}
}
// Imagine several other properties/methods like the above:
int SecondsRemaining;
void UpdateData(IList<int> data);
async Task DoWork2()
{
await Task.Run( () =>
{
StatusCode = DoSomething();
UpdateData(...);
SecondsRemaining = ...;
});
}
async void Caller2(object sender, EventArgs e)
{
await DoWork1();
}
}
是否应该优先使用专用的进度报告机制而不是 Invoke?如果,那为什么?这两种方法是否存在任何可能的“陷阱”?
恕我直言,与ReportProgress 接受具有多个字段的进度结构相比,Invoke 方式更简单/需要更少的代码,特别是如果在任务的多个阶段报告进度并且报告方法因此需要分支到给定阶段的适当报告。
【问题讨论】:
-
“问题代码”与 BeginInvoke 与 Task.Run 无关,因为它们的目的相同。您不妨写:
BeginInvoke(new Action(() => progress.Report(value));以获得更公平的比较 - 在第一个示例中,“要做的事情”在其他地方完成。 -
我认为您误解了 - 问题是关于使用
Invoke与框架的专用进度报告功能。在一种情况下,调用上下文是使用Invoke访问的,在另一种情况下,它被IProgress实现隐式捕获。两个示例都使用Task.Run。 -
请使代码保持一致,除非它应该不同。因为 Task 可以在没有 ReportProgress/IProgress(“更多代码”)的情况下完成,或者 Invoke 可以用它来完成。
-
我更新了示例代码,以更好地反映具有复杂进度报告的真实用例。这个问题是关于实现明显相同结果的两种模式中的哪一种应该被首选,以及为什么。
标签: c# multithreading winforms asynchronous