首页 文章

在TPL中快速抛出未处理的异常

提问于
浏览
3

我的问题:我想在.NET 4和_644366下的WinForms应用程序中使用TPL吗?有可能吗?

在支持 async/await 支持的.NET 4.5中,可以编写:

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 方法中处理,则会立即抛出continuation中的异常 .

如何在没有 async/await 支持的情况下在.NET 4中实现相同的行为?

2 回答

  • 1

    首先,您应该知道可以使用async-await与.Net 4.0一起使用Microsoft.Bcl.Async

    但是没有它,你可以使用 ContinueWith 为任务添加一个延续,并让它只在 TaskContinuationOptions.OnlyOnFaulted 出现异常时运行

    Me.LongWork().ContinueWith(Sub(task) MsgBox(task.Exception.Message), CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted)
    
  • 1

    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
    

    它符合要求 - 抛出异常"fast"并且可以处理 . 异常是 Post 编辑到目标 SynchronizationContext ,因此远离快速和同步的TPL 's exception trapping mechanism. It',但至少它比等待任务处理更好 .

相关问题