問題 非同步操作時,需要展示該操作的進度 解決方案 " " 和 " " 插一段話:讀《C 併發編程經典實例》這本書偶有困惑,深感書中內容過於精煉,或許是作者故意為之,但顯然對我這般知識淺薄的人來說,讀起來這本書感到晦澀。偶然找到作者的個人博客,看到作者博客中對某一個知識點不同時間點上由淺至深的研究,十 ...
問題
非同步操作時,需要展示該操作的進度
解決方案
IProgress<T> Interface
和Progress<T> Class
插一段話:讀《C#併發編程經典實例》這本書偶有困惑,深感書中內容過於精煉,或許是作者故意為之,但顯然對我這般知識淺薄的人來說,讀起來這本書感到晦澀。偶然找到作者的個人博客,看到作者博客中對某一個知識點不同時間點上由淺至深的研究,十分欣喜。作者個人博客地址:https://blog.stephencleary.com/
可查看此書作者博客中相關Progress的文章Reporting Progress from Async Tasks瞭解更多一手知識
文中作者多次提到UI線程,很困惑,因為最近幾年基本沒在工作中寫WPF、WebForm或者WinForm,所以作者說UI線程時很困惑,將其帶入WPF、WebForm或者WinForm的使用場景,就好理解了。
不在廢話,上文中偽代碼例子
static async Task MyMethodAsync(IProgress<double> progress = null)
{
double percentComplete = 0;
while (!done)
{
...
if (progress != null)
progress.Report(percentComplete);
}
}
Progress只有一個Report方法,Report報告進度更改
static async Task CallMyMethodAsync()
{
var progress = new Progress<double>();
progress.ProgressChanged += (sender, args) =>
{
...
};
await MyMethodAsync(progress);
}
註意
IProgress<T>
參數可以為空,這意味著該非同步操作不需要報告更改進度。- Report方法可以是非同步的,這樣的話,MyMethodAsync執行過程中,可能Report方法還未執行,進度還沒有被更新。這樣的話,T最好是一個不可變類型,值類型最好,如果T非要使用可變類型,最好每次Copy一個副本。
- 如果一個方法可以報告進度,最好也應該可以被取消。
- Progress
會在創建時捕獲當前上下文,並且在這個上下文中調用回調函數。這意味著,如果在 UI 線程中創建了 Progress ,就能在 Progress 的回調函數中更新 UI,即使非同步方法是在後臺線程中調用 Report 的。
關於如何使用進度,並可以取消該方法的文章,可查看4.5 中的非同步: 啟用進度和非同步 Api 中的取消
異常
Progress<T>.ProgressChanged
不會拋出異常,或者說它拋出的異常會直接拋給上下文context