我在一个简单的过程(不是类中的方法)中以编程方式创建数据库连接对象。
mydb:= TUniConnection.Create(nil);
mydb.Database:= knowledge_db_name;
mydb.LoginPrompt:= False;
mydb.Username:= aaa;
mydb.Password:= bbb;
现在我需要处理错误并与其他程序断开连接。当我尝试做的时候:
mydb.OnError:= OnConnectionError;
mydb.OnConnectionLost:= OnConnectionLost;
编译器告诉我
[DCC Error] test.pas(373): E2009 Incompatible types: 'method pointer and regular procedure'
我该如何解决这个问题? 以下是事件过程的定义:
procedure OnConnectionError(Sender: TObject; E: EDAError; var Fail: Boolean);
procedure OnConnectionLost(Sender: TObject; Component: TComponent; ConnLostCause: TConnLostCause; var RetryMode: TRetryMode);
答案 0 :(得分:16)
如果您没有合适的类来放置事件处理程序,则可以定义一个虚拟类并生成事件处理程序class procedure
。然后,您不必创建类的实例,但可以分配mydb.OnError:= TMyDummyEventHandlerClass.OnConnectionError;
。
这是一个例子 - 我使用不同的事件,因为我没有TUniConnection
但是想确保所有内容都编译。 : - )
type
// Dummy class to hold event handlers:
TXMLEventHandlers = class
// Event handlers:
class procedure OnBeforeOpen(Sender: TObject);
class procedure OnAfterOpen(Sender: TObject);
end;
class procedure TXMLEventHandlers.OnBeforeOpen(Sender: TObject);
begin
MessageBox(0, PChar(ClassName + '.OnBeforeOpen'), nil, 0)
end;
class procedure TXMLEventHandlers.OnAfterOpen(Sender: TObject);
begin
MessageBox(0, PChar(ClassName + '.OnAfterOpen'), nil, 0)
end;
procedure Test;
var
xml: TXMLDocument;
begin
xml := TXMLDocument.Create(nil);
try
// Note: No instance of `TXMLEventHandlers` must be created:
xml.AfterOpen := TXMLEventHandlers.OnAfterOpen;
xml.BeforeOpen := TXMLEventHandlers.OnBeforeOpen;
xml.Active := True; // Calls the two event handlers
finally
xml.Free;
end;
end;
答案 1 :(得分:4)
如果您不想在堆上实例化类的实例,则可以使用记录方法。我有时会这样做以避免使用堆,但这种方法可以方便您的需求。
type
TMyEventHandler = record
procedure OnConnectionError(Sender: TObject; E: EDAError; var Fail: Boolean);
procedure OnConnectionLost(Sender: TObject; Component: TComponent; ConnLostCause: TConnLostCause; var RetryMode: TRetryMode);
end;
procedure TMyEventHandler.OnConnectionError(Sender: TObject; E: EDAError; var Fail: Boolean);
begin
....
end;
procedure TMyEventHandler.OnConnectionLost(Sender: TObject; Component: TComponent; ConnLostCause: TConnLostCause; var RetryMode: TRetryMode);
begin
....
end;
var
EventHandler: TEventHandler;//global variable
......
mydb.OnError := EventHandler.OnConnectionError;
mydb.OnConnectionLost := EventHandler.OnConnectionLost;
答案 2 :(得分:0)
您的两个事件过程需要是类的方法,而不是本地/全局过程。例如:
procedure TForm1.OnConnectionError(Sender: TObject; E: EDAError; var Fail: Boolean);
答案 3 :(得分:0)
虽然使用class
方法是一种干净的解决方案,但是将常规的非类过程用作事件处理程序是可能,但是您不能为其分配直接,但是您可以使用TMethod
记录将其间接分配。您只需要向该过程中添加一个明确的Self
参数即可。
例如:
procedure OnConnectionError(Self: Pointer; Sender: TObject; E: EDAError; var Fail: Boolean);
begin
...
end;
procedure OnConnectionLost(Self: Pointer; Sender: TObject; Component: TComponent; ConnLostCause: TConnLostCause; var RetryMode: TRetryMode);
begin
...
end;
var
M: TMethod;
begin
M.Data := ... whatever you want ...;
M.Code := @OnConnectionError;
mydb.OnError := TDAConnectionErrorEvent(M);
M.Data := ... whatever you want ...;
M.Code := @OnConnectionLost;
mydb.OnConnectionLost := TConnectionLostEvent(M);
end;
或者:
procedure OnConnectionError(Self: Pointer; Sender: TObject; E: EDAError; var Fail: Boolean);
begin
...
end;
procedure OnConnectionLost(Self: Pointer; Sender: TObject; Component: TComponent; ConnLostCause: TConnLostCause; var RetryMode: TRetryMode);
begin
...
end;
var
ErrorHandler: TDAConnectionErrorEvent;
LostHandler: TConnectionLostEvent;
begin
TMethod(ErrorHandler).Data := ... whatever you want ...;
TMethod(ErrorHandler).Code := @OnConnectionError;
mydb.OnError := ErrorHandler;
TMethod(LostHandler).Data := ... whatever you want ...;
TMethod(LostHandler).Code := @OnConnectionLost;
mydb.OnConnectionLost := LostHandler;
end;
此方法的好处是您可以将Self
参数设置为所需的任何值,这对于将用户定义的数据传递到事件处理程序中很有用。