最佳实践如何在使用链接的CancellationTokenSource时解包CancellationToken

时间:2014-06-05 11:09:33

标签: .net vb.net cancellation

我目前正在我的应用中使用.NET Cancellation Framework。看来我需要时不时地使用链接的CancellationTokenSource,并且我发现在每个匹配的catch中“展开”OperationCanceledException以使其包含正确的CancellationToken是单调乏味的。我想问一下:

  1. 是否有任何开箱即用的解决方案来促进这种情况?
  2. 什么是“最佳实践”处理它?<​​/ li>

    我的问题是关于.NET 4.我还附上代码示例,显示我在说什么:

    Using linkedCts = CancellationTokenSource.CreateLinkedTokenSource(externalCancelToken, internalCancelToken)
        Try
            myRequest.Dispatch(linkedCts.Token)
    
        Catch ex As WebException When ex.Status = WebExceptionStatus.RequestCanceled
            If externalCancelToken.IsCancellationRequested Then
                Throw New OperationCanceledException(externalCancelToken)
            ElseIf internalCancelToken.IsCancellationRequested Then
                Throw New OperationCanceledException(internalCancelToken)
            Else
                Throw
            End If
    
        Catch ex As OperationCanceledException
            If ex.CancellationToken = linkedCts.Token Then
                If externalCancelToken.IsCancellationRequested Then
                    Throw New OperationCanceledException(Nothing, ex, externalCancelToken)
                ElseIf internalCancelToken.IsCancellationRequested Then
                    Throw New OperationCanceledException(Nothing, ex, internalCancelToken)
                End If
            End If
    
        End Try
    End Using
    

1 个答案:

答案 0 :(得分:0)

我试图谷歌一些想法,但没有发现任何东西。所以我想出了以下链接CancellationTokenSource - es:

的包装器
Imports System.Threading


Namespace Threading

    Public Class LinkedCancellationTokenSource
        Implements IDisposable


        Public ReadOnly Property Token As CancellationToken
            Get
                Return Me.internalSource.Token
            End Get
        End Property


        Public ReadOnly Property IsCancellationRequested As Boolean
            Get
                Return Me.internalSource.IsCancellationRequested
            End Get
        End Property


        Private ReadOnly tokens As CancellationToken()
        Private ReadOnly internalSource As CancellationTokenSource


        Private Sub New(internalSource As CancellationTokenSource, tokens As CancellationToken())
            Me.internalSource = internalSource
            Me.tokens = tokens
        End Sub


        Public Sub Cancel()
            Me.internalSource.Cancel()
        End Sub


        ''' 
        ''' Tries to unwrap  to any contained 
        '''  in this source. If token in exception is unknown,
        ''' nothing will be thrown and you have to elevate.
        ''' 
        ''' Caught exception which should be unwrapped.
        ''' Message which will be appended to the unwrapped exception.
        Public Sub ThrowIfCausedCancelOf(ex As OperationCanceledException, Optional message As String = Nothing)
            If ex.CancellationToken = Me.Token Then
                Me.ThrowIfAnyCancellationRequested(ex, message)
            End If
        End Sub


        ''' 
        ''' Throws  if any of contained tokens has had 
        ''' cancellation requested.
        ''' 
        Public Sub ThrowIfCancellationRequested()
            Me.ThrowIfCancellationRequested(Nothing, Nothing)
        End Sub


        ''' 
        ''' Throws  if any of contained tokens has had 
        ''' cancellation requested.
        ''' 
        Public Sub ThrowIfCancellationRequested(message As String)
            Me.ThrowIfCancellationRequested(Nothing, message)
        End Sub


        ''' 
        ''' Throws  if any of contained tokens has had 
        ''' cancellation requested.
        ''' 
        Public Sub ThrowIfCancellationRequested(ex As Exception, Optional message As String = Nothing)
            For i = 0 To Me.tokens.Length - 1
                If Me.tokens(i).IsCancellationRequested Then
                    Throw New OperationCanceledException(message, ex, Me.tokens(i))
                End If
            Next
        End Sub


        Public Shared Function Create(token1 As CancellationToken, token2 As CancellationToken) As LinkedCancellationTokenSource
            Dim internalSource = CancellationTokenSource.CreateLinkedTokenSource(token1, token2)
            Return New LinkedCancellationTokenSource(internalSource, {token1, token2})
        End Function


        Public Shared Function Create(ParamArray tokens As CancellationToken()) As LinkedCancellationTokenSource
            Dim internalSource = CancellationTokenSource.CreateLinkedTokenSource(tokens)
            Return New LinkedCancellationTokenSource(internalSource, tokens)
        End Function

#Region "IDisposable Support"
        Private disposedValue As Boolean ' To detect redundant calls

        ' IDisposable
        Protected Overridable Sub Dispose(disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    ' dispose managed state (managed objects).
                    Me.internalSource.Dispose()
                End If

                ' free unmanaged resources (unmanaged objects) and override Finalize() below.
                ' set large fields to null.
            End If
            Me.disposedValue = True
        End Sub

        ' override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
        'Protected Overrides Sub Finalize()
        '    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        '    Dispose(False)
        '    MyBase.Finalize()
        'End Sub

        ' This code added by Visual Basic to correctly implement the disposable pattern.
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub

#End Region

    End Class

End Namespace

上述示例中的用法:

Using linkedCts = LinkedCancellationTokenSource.Create(externalCancelToken, internalCancelToken)
    Try
        myRequest.Dispatch(linkedCts.Token)

    Catch ex As WebException When ex.Status = WebExceptionStatus.RequestCanceled
        linkedCts.ThrowIfCancellationRequested(ex)
        Throw

    Catch ex As OperationCanceledException
        linkedCts.ThrowIfCausedCancelOf(ex)
        Throw

    End Try
End Using

请向上/向下投票决定这是好还是坏的解决方案。此外,欢迎更好地命名方法的想法。