Delphi 在TDatasetProvider.OnUpdateError中引发时无法识别EUpdateError异常。为什么?
当我在Delphi 在TDatasetProvider.OnUpdateError中引发时无法识别EUpdateError异常。为什么?,delphi,delphi-2009,Delphi,Delphi 2009,当我在TDatasetProvider.OnUpdateError事件中重新抛出EUpdateError异常时,它在catch块中不会被识别为EUpdateError异常。它只被识别为基本exoption try ... //calls the TDatasetPorvider.OnUpdateError event. myClientDataSet.ApplyUpdates(0); ... except on ex: EUpdateError do begin //n
TDatasetProvider.OnUpdateError
事件中重新抛出EUpdateError
异常时,它在catch块中不会被识别为EUpdateError
异常。它只被识别为基本exoption
try
...
//calls the TDatasetPorvider.OnUpdateError event.
myClientDataSet.ApplyUpdates(0);
...
except
on ex: EUpdateError do
begin
//never goes here
//Evaluate ex.ErrorCode
end;
on ex: Exception do
begin
//always goes here
//the expression (ex is EUpdateError) returns false;
end;
end;
Hiere是相应的.onUpdate错误
实现:
procedure MyDataModule.MyDatasetProviderOnUpdateError(..;E: EUpdateError;...);
beign
//Here, the expression (E is EUpdateException) returns true;
raise E;
end;
异常被重新抛出,但似乎EUpdateError
被转换为普通的基本执行选项。有人知道为什么这类人会迷路吗
我需要该类型来检查
.ErrorCode
,以了解出了什么问题并准备正确的用户消息。不幸的是,“旧式”DataSnap服务器异常仅作为文本(例如消息)封送到客户端,因此异常类名和实例数据在此过程中丢失。请参阅SConnect
单元,tdatablockexplorer.interpretatdata
方法(块除外)
编辑:这里有一个非常简单的例子,给你一个想法(根本没有经过测试):
是否有方法将(sql/数据库)错误代码发送到try-except块,以便区分错误消息(以便对错误代码做出决定)?是的,但您必须修改并重新生成服务器和客户端可执行文件。您可以包含类名并使用一些实用程序函数来流式处理特定的异常实例数据,例如SQL错误代码。TDataSetProvider和TClientDataSet组件位于同一个DataModule(它是一个可执行文件)中。即使对于单个可执行文件,原理仍然是一样的:服务器代码(提供程序)“发送”异常(目前,仅发送其消息以及asError标志)因此,您必须修改该代码以包含异常类名和实例数据。客户端代码必须能够识别异常类,以便读取和解释实例数据。有没有简单的方法可以做到这一点?我不知道去哪里,怎么做。或者,您有简短的示例代码吗?
// new methods
function TDataBlockInterpreter.ReadException(const Data: IDataBlock): Exception;
var
Flags: TVarFlags;
AClassName, AMessage, AContext: string;
ErrorCode, PreviousError: Integer;
OriginalException: Exception;
begin
AClassName := ReadVariant(Flags, Data);
AMessage := ReadVariant(Flags, Data);
if AClassName = 'EUpdateError' then
begin
AContext := ReadVariant(Flags, Data);
ErrorCode := ReadVariant(Flags, Data);
PreviousError := ReadVariant(Flags, Data);
OriginalException := ReadException(Data);
Result := EUpdateError.Create(AMessage, AContext, ErrorCode, PreviousError, OriginalException);
end
// else if AClassName = ... then ...
else
Result := Exception.Create(AMessage);
end;
procedure TDataBlockInterpreter.WriteException(E: Exception; const Data: IDataBlock);
begin
WriteVariant(E.ClassName, Data);
WriteVariant(E.Message, Data);
if E is EUpdateError then
begin
WriteVariant(EUpdateError(E).Context, Data);
WriteVariant(EUpdateError(E).ErrorCode, Data);
WriteVariant(EUpdateError(E).PreviousError, Data);
WriteException(EUpdateError(E).OriginalException, Data);
end;
end;
// modified methods
procedure TDataBlockInterpreter.DoException(const Data: IDataBlock);
begin
raise ReadException(Data);
end;
procedure TDataBlockInterpreter.InterpretData(const Data: IDataBlock);
var
Action: Integer;
begin
Action := Data.Signature;
if (Action and asMask) = asError then DoException(Data);
try
case (Action and asMask) of
asInvoke: DoInvoke(Data);
asGetID: DoGetIDsOfNames(Data);
asCreateObject: DoCreateObject(Data);
asFreeObject: DoFreeObject(Data);
asGetServers: DoGetServerList(Data);
asGetAppServers: DoGetAppServerList(Data);
else
if not DoCustomAction(Action and asMask, Data) then
raise EInterpreterError.CreateResFmt(@SInvalidAction, [Action and asMask]);
end;
except
on E: Exception do
begin
Data.Clear;
Data.Signature := ResultSig or asError;
WriteException(E, Data);
FSendDataBlock.Send(Data, False);
end;
end;
end;