C#转VB.Net后Delegate事件调用报错,如何正确使用RaiseEvent?
我是Delegate新手,将一段C#的连接状态变更事件相关代码转换为VB.Net后,在调用ConnectionStatusChanged事件的BeginInvoke和EndInvoke方法时,出现BC32022错误,提示事件无法直接调用,需使用RaiseEvent语句。但我不清楚原代码的具体逻辑,也不知道RaiseEvent的处理程序应该如何编写,希望得到帮助。
原C#代码
public delegate void delConnectionStatusChanged(EventDrivenTCPClient sender, ConnectionStatus status); public event delConnectionStatusChanged ConnectionStatusChanged; private ConnectionStatus _ConStat; public ConnectionStatus ConnectionState { get { return _ConStat; } private set { bool raiseEvent = value != _ConStat; _ConStat = value; if (ConnectionStatusChanged != null && raiseEvent) ConnectionStatusChanged.BeginInvoke(this, _ConStat, new AsyncCallback(cbChangeConnectionStateComplete), this); } } private void cbChangeConnectionStateComplete(IAsyncResult result) { var r = result.AsyncState as EventDrivenTCPClient; if (r == null) throw new InvalidOperationException("Invalid IAsyncResult - Could not interpret as a EDTC object"); r.ConnectionStatusChanged.EndInvoke(result); }
转换后的VB.Net代码
Public Delegate Sub delConnectionStatusChanged(ByVal sender As EventDrivenTCPClient, ByVal status As ConnectionStatus) Public Event ConnectionStatusChanged As delConnectionStatusChanged Private _ConStat As ConnectionStatus Public Property ConnectionState As ConnectionStatus Get Return _ConStat End Get Private Set(ByVal value As ConnectionStatus) Dim [raiseEvent] As Boolean = value <> _ConStat _ConStat = value If ConnectionStatusChanged IsNot Nothing AndAlso [raiseEvent] Then ConnectionStatusChanged.BeginInvoke(Me, _ConStat, New AsyncCallback(AddressOf cbChangeConnectionStateComplete), Me) End Set End Property Private Sub cbChangeConnectionStateComplete(ByVal result As IAsyncResult) Dim r = TryCast(result.AsyncState, EventDrivenTCPClient) If r Is Nothing Then Throw New InvalidOperationException("Invalid IAsyncResult - Could not interpret as a EDTC object") r.ConnectionStatusChanged.EndInvoke(result) End Sub
报错信息
Error BC32022 'Public Event ConnectionStatusChanged As EventDrivenTCPClient.delConnectionStatusChanged' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
(中文翻译:错误 BC32022:“Public Event ConnectionStatusChanged As EventDrivenTCPClient.delConnectionStatusChanged”是一个事件,无法直接调用。请使用“RaiseEvent”语句引发事件。)
解决方案
原代码逻辑解析
原C#代码核心逻辑:当ConnectionState属性值发生变化时,异步触发ConnectionStatusChanged事件,通过BeginInvoke异步调用事件处理程序,再通过回调方法cbChangeConnectionStateComplete调用EndInvoke完成异步操作的清理。
VB.Net修正代码
VB.Net对事件封装更严格,类内部无法直接对事件调用BeginInvoke/EndInvoke,必须先获取事件对应的委托实例再操作。修正后的代码如下:
Public Delegate Sub delConnectionStatusChanged(ByVal sender As EventDrivenTCPClient, ByVal status As ConnectionStatus) Public Event ConnectionStatusChanged As delConnectionStatusChanged Private _ConStat As ConnectionStatus Public Property ConnectionState As ConnectionStatus Get Return _ConStat End Get Private Set(ByVal value As ConnectionStatus) Dim raiseEvent As Boolean = value <> _ConStat _ConStat = value ' 先获取事件对应的委托实例,避免直接操作事件 Dim handler As delConnectionStatusChanged = ConnectionStatusChanged If handler IsNot Nothing AndAlso raiseEvent Then ' 将委托实例传入AsyncState,供回调方法使用 handler.BeginInvoke(Me, _ConStat, AddressOf cbChangeConnectionStateComplete, handler) End If End Set End Property Private Sub cbChangeConnectionStateComplete(ByVal result As IAsyncResult) ' 从AsyncState中取出委托实例 Dim handler As delConnectionStatusChanged = TryCast(result.AsyncState, delConnectionStatusChanged) If handler Is Nothing Then Throw New InvalidOperationException("Invalid IAsyncResult - 无法转换为delConnectionStatusChanged委托") End If ' 调用委托的EndInvoke完成异步操作 handler.EndInvoke(result) End Sub
关键修正说明
- 获取委托实例:将
ConnectionStatusChanged事件赋值给局部变量handler,这是VB.Net允许调用委托方法的前提,避免直接操作事件。 - 传递委托到回调:把
handler作为BeginInvoke的AsyncState参数传入,回调方法中直接通过该参数获取委托实例,调用EndInvoke完成异步清理,规避VB.Net不能通过实例访问事件方法的限制。
内容的提问来源于stack exchange,提问作者Tim Makins

