在运行时期间从EventHandler`1到EventHandler的InvalidCastException - 但它之前有效

时间:2014-12-05 15:00:39

标签: .net vb.net events exception casting

我正在InvalidCastException EventHandler`1 投射到之前运行过的代码中的 EventHandler ,并且我知道没有相关内容变化。 (我有新旧版本。)

有趣的是我一直使用这种类型。 我不明白为什么甚至会将EventHandler`1扩展到EventHandler。请参阅附带的源摘录:

基础是这样的:

Option Strict On
Option Explicit On
Option Infer Off

Public Class CapturedEventArgs
    Inherits EventArgs

    Property Handled As Boolean
    Property Processor As clsScannerProcessor
    Property Scan As String
End Class

Public Class clsScannerProcessor

    Public Event CapturedInProcessor As EventHandler(Of CapturedEventArgs)

    'executed in background thread
    Sub EvaluateScan()
        'excerpt: ... on valid scan pattern
        Dim cea As New CapturedEventArgs() With {.Scan = _scan,
                                                 .Processor = Me,
                                                 .Handled = False}
        _mainContext.Send(AddressOf RaiseCapturedInProcessorEvent, cea)  'EXCEPTION HERE
     End Sub

    'executed in main thread
    Private Sub RaiseCapturedInProcessorEvent(e As Object)
        RaiseEvent CapturedInProcessor(Me, DirectCast(e, CapturedEventArgs))
    End Sub

End Class

请知道为什么这些类型在运行时突然不兼容?在我没有对继承类型进行任何更改之前,代码工作正常。

我添加的内容是此类事件的自定义事件中继。据我了解,它不应该相关。

完整的例外文字:

System.InvalidCastException was unhandled
  Message=Unable to cast object of type 'System.EventHandler`1[myProject.clsScannerProcessor+CapturedEventArgs]' to type 'System.EventHandler'.
  Source=System.Windows.Forms
  StackTrace:
       at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
       at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
       at System.Windows.Forms.WindowsFormsSynchronizationContext.Send(SendOrPostCallback d, Object state)
       at vpsCRMsql.clsScannerProcessor.EvaluateScan() in ...
       at vpsCRMsql.clsScannerProcessor.EvaluateKeystroke(stQueuedEvent keyEvent) in ...
       at vpsCRMsql.clsScannerProcessor.WatchQueue() in ...
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)

整体模型:

多个设备处理器(在不同的线程中运行)引发自己的事件,这些事件将转发到事件中继以引发一个公共事件。

事件中继(在 clsScannerManager 类中管理上述 clsScannerProcessor 的一个或多个实例)如下所示:

Public Class clsScannerManager

    Public Custom Event Captured As EventHandler(Of clsScannerProcessor.CapturedEventArgs)
        AddHandler(ByVal value As EventHandler(Of clsScannerProcessor.CapturedEventArgs))
            _eventReceivers.Add(value)
        End AddHandler
        RemoveHandler(value As EventHandler(Of clsScannerProcessor.CapturedEventArgs))
            _eventReceivers.Remove(value)
        End RemoveHandler
        RaiseEvent(sender As Object, e As clsScannerProcessor.CapturedEventArgs)
            For Each handler As EventHandler In _eventReceivers
                'some more complex work in here
            Next
        End RaiseEvent
    End Event

    Sub AddEventToProcessor(processor As clsScannerProcessor)
        AddHandler processor.CapturedInProcessor, AddressOf RaiseCapturedEvent
    End Sub

    Sub RaiseCapturedEvent(sender As Object, e As clsScannerProcessor.CapturedEventArgs)
        RaiseEvent Captured(sender, e)
    End Sub

2 个答案:

答案 0 :(得分:1)

只是一个预感,但应该看起来像这样:

For Each handler As EventHandler In _eventReceivers

实际上看起来像这样

For Each handler As EventHandler(Of clsScannerProcessor.CapturedEventArgs) In _eventReceivers

Private _eventReceivers As New ArrayList()

实际上应该是这样的:

Private _eventReceivers As New List(Of EventHandler(Of clsScannerProcessor.CapturedEventArgs))

您获得的例外来自For Each行。变量_eventReceivers有一组对象,它们的类型为EventHandler(Of clsScannerProcessor.CapturedEventArgs),尽管引用实际上存储为对象。无法将EventHandler(of clsScannerProcessor.CapturedEventArgs)强制转换为EventHandler,因此抛出了强制转换异常。通过WindowsFormsSynchronizationContext.Send的调用会截断调用堆栈。

答案 1 :(得分:0)

我为学习目的添加了这个答案。

棘手的部分是代码中VS 2012中抛出异常的地方:

_mainContext.Send(AddressOf RaiseCapturedInProcessorEvent, cea)  'EXCEPTION HERE

实际问题是RaiseCapturedInProcessorEvent调用内部的几个级别(并且它在接受的答案中显示的很明显),但异常未在Send() 之前显示

InvalidCastException误导我认为Send()参数存在问题。