让我们假设这段代码:
模块1:
$(document).ready(function (){
$("#matricola").keyup(function (e) {
var thevalue = $(this).val();
$.post('getMatricolaAjax.php',{'type':'user','matricola':thevalue},
function(data) {
console.log("OK");
$("#matricola").val("");
alert("Matricola "+ data +" già presente!!");
});
});
});
的Class1:
<?php
require_once 'config.php';
require_once FUNCTION_PATH.'/dbFunction.php';
$conn = dbConnect($USERDB, $PASSWORDDB, $NAMEDB);
if($conn->real_escape_string($_POST['type']) == "user"){
$queryMatricolaMatch = 'select * from user where matricola = "'.$conn->real_escape_string($_POST['matricola']).'"';
}else{
$queryMatricolaMatch = 'select * from 150ore where matricola = "'.$conn->real_escape_string($_POST['matricola']).'"';
}
$matricola = dbQueryGetResult($queryMatricolaMatch);
dbDisconnect($conn);
echo $matricola;
等级2:
Sub main()
Dim cl As New Class2
On Error GoTo errorhandler1
cl.DoWork
On Error GoTo 0
Exit Sub
errorhandler1:
MsgBox (Err.Description)
End Sub
我希望启动errorhandler1并显示带有err.Description的MsgBox。 但它反而引发了我的运行时错误。
我需要做些什么来处理EventHandlers例程中的错误?
答案 0 :(得分:3)
这只是咬了我 - 你在这个简单的C#代码中看到了:
try
{
SomeEvent?.Invoke(this, EventArgs.Empty);
}
catch
{
// break here
}
如果SomeEvent
的任何处理程序抛出异常,AFAIK会在catch
块中中出现断点 - 而且我期待VBA也这样做...它没有。
通过打破事件处理程序,然后检查调用堆栈,您可以看到某些在事件源与RaiseEvent
调用之间滑动,以及事件处理程序过程:
我认为[<Non-Basic code>]
这里将是VBA运行时本身,将事件分派给正在侦听该特定事件源实例上的事件的任何对象:这个“中间人”很可能为什么运行时错误没有冒泡:运行时可能会保护自己并在此处抛出错误,无论父堆栈帧是否有On Error
语句。
您可以在该屏幕截图中看到我的解决方法的一些提示 - 添加一个新的类模块,将其命名为ErrorInfo
,并为其提供一些有用的成员:
Option Explicit
Private Type TErrorInfo
Number As Long
Description As String
Source As String
End Type
Private this As TErrorInfo
Public Property Get Number() As Long
Number = this.Number
End Property
Public Property Get Description() As String
Description = this.Description
End Property
Public Property Get Source() As String
Source = this.Source
End Property
Public Property Get HasError() As Boolean
HasError = this.Number <> 0
End Property
Public Property Get Self() As ErrorInfo
Set Self = Me
End Property
Public Sub SetErrInfo(ByVal e As ErrObject)
With e
this.Number = .Number
this.Description = .Description
this.Source = .Source
End With
End Sub
现在无论何时定义事件,都要为其添加一个参数:
Public Event Something(ByVal e As ErrorInfo)
当引发该事件时,提供实例,处理错误,检查ErrorInfo
对象,相应地调用Err.Raise
,然后你可以处理 > em>错误通常,在事件调用范围中,您希望处理事件处理程序错误:
Public Sub DoSomething()
On Error GoTo CleanFail
With New ErrorInfo
RaiseEvent Something(.Self)
If .HasError Then Err.Raise .Number, .Source, .Description
End With
Exit Sub
CleanFail:
MsgBox Err.Description, vbExclamation
End sub
事件处理程序代码只需处理其错误(否则处理程序中的任何运行时错误基本上都是未处理的),并在ErrInfo
参数中设置错误状态:
Private Sub foo_Something(ByVal e As ErrorInfo)
On Error GoTo CleanFail
Err.Raise 5
Exit Sub
CleanFail:
e.SetErrInfo Err
End Sub
和bingo,现在你可以干净地处理在事件源中的事件处理程序中引发的错误,而不涉及全局变量或losing the actual error information(在我的情况下,在某些第三方API中引发的错误)无用(但在大多数情况下可以说是“足够好”)“哎呀,没有用”信息。
与Cancel
事件的情况一样,如果一个事件有多个处理程序,那么哪个状态返回到事件调用站点是,未定义 - 如果只有一个处理程序抛出一个错误,并且非投掷处理程序不会篡改ErrorInfo
参数,那么理论上调用站点会出现一个错误。当两个或多个处理程序抛出错误时,“乐趣”就开始了。
在这种情况下,处理程序需要在修改ErrorInfo
之前验证ErrorInfo
的状态。
或者,另一个解决方案可能是让Property Get
类封装错误信息的数组,并可能将索引器添加到ErrorInfo
成员 - 或者其他任何机制可以考虑,“汇总错误”。哎呀,您甚至可以在AggregateErrorInfo
集合类中封装{em>集合的public async Task CreatePictureFolderAsync()
{
try
{
var folder = await DownloadsFolder.CreateFolderAsync("Pictures");
// add your folder to StorageApplicationPermissions.FutureAccessList
StorageApplicationPermissions.FutureAccessList.AddOrReplace(token, folder);
}
catch (Exception ex) { ex.Exception("CreatePictureFolderAsync"); }
}
个实例,并使您的“多个侦听器事件”在其签名中使用它。
大多数时候你只需要一个处理程序,所以这不是一个问题。
答案 1 :(得分:2)
我们可以阅读here:
如果您使用Err对象的Raise方法引发错误,那么 可以强制Visual Basic通过调用列表向后搜索 启用的错误处理程序。
但在这种情况下,没有启用错误处理程序。
也许您可以通知class2的客户端工作失败。这里因为class2的客户端是一个标准模块,你不能使用class2中的事件,所以也许只是一个简单的只读属性可能会有帮助吗?
模块:
Sub main()
cl.DoWork
If Not cl.IsWorkOk Then MsgBox "Work failed..."
On Error GoTo 0
Exit Sub
errorhandler1:
MsgBox (Err.Description)
End Sub
等级2:
Private m_isWorkOk As Boolean
Private Sub cl_MyEvent()
On Error GoTo ErrMyEvent
Call Err.Raise(123, , "ErrorInClass")
m_isWorkOk = True
Exit Sub
ErrMyEvent:
m_isWorkOk = False
End Sub
Public Property Get IsWorkOk() As Boolean
IsWorkOk = m_isWorkOk
End Property