我最近第一次使用異步(和.Net 4.5),我遇到了一些讓我難堪的東西。關於在網上可以找到的VoidTaskResult類沒有太多的信息,所以我來這裏看看是否有人對發生了什麼有什麼想法。什麼是VoidTaskResult類型與異步方法有關?
我的代碼如下所示。顯然,這非常簡單。基本的想法是調用異步的插件方法。如果他們返回任務,那麼異步調用沒有返回值。如果他們返回任務<>,那麼有。我們事先並不知道它們是哪種類型,因此我們的想法是使用反射來查看結果的類型(如果類型爲<>,則IsGenericType爲true)並使用動態類型獲取該值。
在我的真實代碼中,我通過反射調用了插件方法。我認爲這不會對我所看到的行爲產生影響。
// plugin method
public Task yada()
{
// stuff
}
public async void doYada()
{
Task task = yada();
await task;
if (task.GetType().IsGenericType)
{
dynamic dynTask = task;
object result = dynTask.Result;
// do something with result
}
}
這適用於上面顯示的插件方法。 IsGenericType爲false(如預期)。
但是如果你改變了插件的方法的聲明非常輕微,IsGenericType現在返回true,東西遊:
public async Task yada()
{
// stuff
}
當你做到這一點,下面的異常被拋出就行了(對象result = dynTask.Result):
如果你深入到任務對象,它實際上似乎是類型。 VoidTaskResult是線程名稱空間中的私有類型,幾乎沒有任何內容。
我試圖改變我的調用代碼:
public async void doYada()
{
Task task = yada();
await task;
if (task.GetType().IsGenericType)
{
object result = task.GetType().GetProperty("Result").GetMethod.Invoke(task, new object[] { });
// do something with result
}
}
這種「成功」,在某種意義上說,它不會再發生,但現在的結果是類型爲「VoidTaskResult」的,我不能理智做任何事情。
我應該補充說,即使爲這一切制定真正的問題,我也很難。也許我真正的問題是「什麼是VoidTaskResult?」,或者「爲什麼動態調用異步方法時發生這種奇怪的事情?」甚至可能「如何調用可選異步的插件方法?」無論如何,我正在把這件事放在那裏,希望其中一位大師能夠闡明一些事情。
爲什麼異步團隊引入VoidTaskResult而不是引入非泛型的TaskCompletionSource? – Puppy
@Puppy:我懷疑是因爲它的工作量少了很多。編寫一個非泛型'TaskCompletionSource'並不難,但任何公共API必須經過一堆其他「門」才能發佈。安全評論等等。 –