私の問題:私は.NET 4のWinFormsアプリケーションでTPLを使いたい待っているのではなく、未処理の例外を即座に上げる( "fast throw")ためのタスク継続が必要です。GC
を集めるTask
。出来ますか?
.NET 4.5ではasync/await
それは書くことが可能ですサポート:
Public Class AwaitForm Inherits Form Private Async Sub Execute() Dim uiScheduler = TaskScheduler.FromCurrentSynchronizationContext() Try Await Me.LongWork(). ContinueWith(Sub(t) Me.LongWorkCompleted(), uiScheduler) Catch ex As Exception ' yay, possible to handle here ' eg. MsgBox(ex.Message) Throw End Try End Sub Private Async Function LongWork() As Task Await Task.Delay(1000) End Function Private Sub LongWorkCompleted() Throw New Exception("Ups") End Sub End Class
で処理されないと、継続中の例外がただちにスローされます。Excecute
方法。
なしで.NET 4で同じ動作を実現する方法async/await
サポート?
まず最初に、.Net 4.0でasync-awaitを使用することが可能であることを知っておくべきです。Microsoft.Bcl.Async
しかし、それがなければ、次のようにしてタスクに継続を追加できます。ContinueWith
そして、例外があったときだけそれを走らせますTaskContinuationOptions.OnlyOnFaulted
Me.LongWork().ContinueWith(Sub(task) MsgBox(task.Exception.Message), CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted)
1)どちらでも使えますMicrosoft.Bcl.Async
i3arnonが示唆しているように。
2)または、あなたが追加のライブラリを参照したくないならば、私はに基づく解決策を思い付きましたasync/await
。背後にある魔法は幸運ですが、それは私が持っていることが最高です。
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Threading
Public Module TaskExtensions
''' <summary>Throws the exception on the current SynchronizationContext or ThreadPool if there is none.</summary>
''' <param name="task">Task whose faulted continuation should throw exception.</param>
<Extension()>
Public Sub ThrowOnFaulted(task As Task)
Dim context = SynchronizationContext.Current
ThrowOnFaulted(task, context)
End Sub
''' <summary>Throws the exception on the ThreadPool in given context.</summary>
''' <param name="task">Task whose faulted continuation should throw exception.</param>
''' <param name="targetContext">The target context on which to propagate the exception. Null to use the ThreadPool.</param>
<Extension()>
Public Sub ThrowOnFaulted(task As Task, targetContext As SynchronizationContext)
task.ContinueWith(Sub(t) ThrowOnFaultedCore(t, targetContext), TaskContinuationOptions.OnlyOnFaulted)
End Sub
''' <remarks>Taken from System.RunTime.CompilerServices.AsyncServices.</remarks>
Private Sub ThrowOnFaultedCore(task As Task, targetContext As SynchronizationContext)
Dim exception = task.Exception
If targetContext IsNot Nothing Then
Try
targetContext.Post(Sub(state) Throw DirectCast(state, Exception), exception)
Return
Catch ex As Exception
exception = New AggregateException({exception, ex})
End Try
End If
ThreadPool.QueueUserWorkItem(Sub(state) Throw DirectCast(state, Exception), exception)
End Sub
End Module
それは要件を満たしています - 例外は "速く"投げられそして処理することができます。例外はPost
ターゲットにedSynchronizationContext
したがって、TPLの例外トラップメカニズムを回避します。高速で同期的ではありませんが、少なくともタスクの破棄を待つよりも動作が優れています。
Task.Wait
しかし、それからTPLを使用して始めても意味がありません。 - i3arnonWait
トリックを行いますが、私はしたくないUIスレッドをブロックします。 &quot;したいWait
&quot;例外がスローされるとすぐに、と継続しているWait
繰り返しますが、未処理の例外はTPLによってトラップされます。 - mancze