【问题标题】:InvalidCastException from EventHandler`1 to EventHandler during runtime – but it worked before在运行时从 EventHandler`1 到 EventHandler 的 InvalidCastException - 但它之前工作过
【发布时间】:2015-02-03 18:58:46
【问题描述】:

我收到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

【问题讨论】:

  • Captured事件的定义在哪里?在我看来,这才是关键。
  • @roryap - 我还添加了一些其他可能很重要的东西(对不起,因为添加了很长的问题)

标签: .net vb.net events exception casting


【解决方案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 的调用会截断调用堆栈。

【讨论】:

  • Private _eventReceivers As New ArrayList()。谢谢你。主要的奇怪问题仍然存在,甚至不知道它是如何可能的。
  • 难以置信,你是对的。我很惊讶为什么我在网上遇到异常,你可以看到评论'EXCEPTION HERE(不同的班级等)。也许这可以通过在执行离开旧线程的地方以棘手的方式报告来自另一个线程的异常的行为来解释。
【解决方案2】:

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

棘手的部分是在 VS 2012 中引发异常的代码位置:

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

实际问题是RaiseCapturedInProcessorEvent 的调用内部级别很少(这与接受的答案中显示的一样明显),但没有比Send() 更早地显示异常

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-22
    相关资源
    最近更新 更多