在下面的代码中,我定义了两种方法指针类型。我需要另一个接受任何这些类型的参数的过程,并根据其他值使用它。但是我找不到这两种类型的基类型能够将两者都传递到过程中:
type
TIntProc: procedure (I: Integer) of object;
TStrProc: procedure (S: string) of object;
....
procedure TForm1.CallbackTest(A: Integer; Callback: procedure of object {What type should I use here?});
var
IntProc: TIntProc;
StrProc: TStrProc;
begin
if A = 1 then begin
IntProc:= TIntProc(Callback);
IntProc(100);
end else begin
StrProc:= TStrProc(Callback);
StrProc('Hello');
end;
end;
procedure TForm1.MyIntProc(I: Integer);
begin
ShowMessage(IntToStr(I));
end;
procedure TForm1.MyStrProc(S: string);
begin
ShowMessage(S);
end;
我应该写:
CallbackTest(1, MyIntProc);
还有:
CallbackTest(2, MyStrProc);
但当然我在两者上都会出错,因为procedure of object
用作第二个参数的类型不是procedure (I: Integer) of object
和procedure (S: string) of object
的基本类型。任何想法如何做到这一点?
答案 0 :(得分:3)
程序类型没有继承。您不能通过单个参数传递任何类型的类型安全方法。你需要施展。例如,您可以在程序类型变量和typecast之间TMethod
。
// Health warning, this code is for illustration, I do not endorse its use
procedure Foo(A: Integer; Callback: TMethod);
begin
if A = 1 then
TIntProc(Callback)(100)
else
TStrProc(Callback)('Hello');
end;
....
Foo(1, TMethod(IntProc));
Foo(2, TMethod(StrProc));
但如果有更好的方法,我不会推荐这种方法。尤其是因为您必须使用未经检查的强制转换,因此甚至不会受益于具有as
运算符的类的运行时检查。
我个人以不同的方式解决这个问题:
public
procedure Foo(Callback: TIntProc); overload;
procedure Foo(Callback: TStrProc); overload;
如果您需要一个例程来处理这两个回调方法,请进行额外的私有重载:
private
procedure Foo(IntCallback: TIntProc; StrCallback: TStrProc); overload;
像这样实施:
procedure TMyClass.Foo(IntCallback: TIntProc; StrCallback: TStrProc);
begin
if Assigned(IntCallback) then
....
if Assigned(StrCallback) then
....
end;
然后实现像这样的公共重载:
procedure TMyClass.Foo(Callback: TIntProc);
begin
Foo(Callback, nil);
end;
procedure TMyClass.Foo(Callback: TStrProc);
begin
Foo(nil, Callback);
end;
答案 1 :(得分:2)
通过一些通用的帮助,这是可能的:
program Project14;
{$APPTYPE CONSOLE}
uses
System.SysUtils,TypInfo;
Type
TMyProcedures = record
procedure MyIntProc(I: Integer);
procedure MyStrProc(S: String);
end;
TMyRec = record
public
class procedure CallbackTest<T>( Callback: TProc<T>); static;
end;
class procedure TMyRec.CallbackTest<T>( Callback: TProc<T>);
begin
case GetTypeKind(T) of
tkInteger:
begin
if GetTypeData(TypeInfo(T))^.OrdType = otSLong then
TProc<Integer>(Callback)(100);
end;
tkUString:
TProc<String>(Callback)('Hello');
end;
else raise Exception.Create('Callback type can only be string or integer');
end;
procedure TMyProcedures.MyIntProc(I: Integer);
begin
WriteLn(IntToStr(I));
end;
procedure TMyProcedures.MyStrProc(S: string);
begin
WriteLn(S);
end;
var
myProcedures: TMyProcedures;
begin
TMyRec.CallbackTest<Integer>(myProcedures.MyIntProc);
TMyRec.CallbackTest<String>(myProcedures.MyStrProc);
ReadLn;
end.
通过TypeInfo
调用解决了这种方法,并且类型转换修复了回调方法。
对于Delphi XE7之前的版本,您可以使用以下代码CallBackTest
class procedure TMyRec.CallbackTest<T>( Callback: TProc<T>);
begin
if TypeInfo(T) = TypeInfo(Integer) then begin
if GetTypeData(TypeInfo(T))^.OrdType = otSLong then
TProc<Integer>(Callback)(100);
end
else if TypeInfo(T) = TypeInfo(String) then begin
TProc<String>(Callback)('Hello');
end
else raise Exception.Create('Callback type can only be string or integer');
end;
<子> 使用类型安全的方式更新,将实际的序数类型分隔为适用于Delphi 2009..XE6的整数和代码。 子>