是否可以使用默认参数创建函数指针,例如
TFunctionPointer = function(sName:AnsiString; tOptional: TObject = nil):smallint;
我想要达到的目标:
一个函数指针,可以接受一个函数类型
function A(sName:AnsiString)
或者
function B(sName:AnsiString, tOptional: TObject)
我怎样才能做到这一点?
是否可以使用默认参数创建函数指针,例如
TFunctionPointer = function(sName:AnsiString; tOptional: TObject = nil):smallint;
我想要达到的目标:
一个函数指针,可以接受一个函数类型
function A(sName:AnsiString)
或者
function B(sName:AnsiString, tOptional: TObject)
我怎样才能做到这一点?
默认参数只是一个语法糖——实际上函数调用有两个参数。
但是你可以使用函数引用和匿名方法来创建这样的函数指针——函数适配器。
type
fnA = function(const sName: AnsiString): integer;
fnB = function(const sName: AnsiString; const tOptional: TObject); integer;
fnRef = reference to function(const sName: AnsiString; const tOptional: TObject): integer;
fnBridge = record
Bridge: fnRef;
class operator Implicit(fn: fnA): fnBridge;
class operator Implicit(fn: fnB): fnBridge;
end;
class operator fnBridge.Implicit(fn: fnA): fnBridge;
begin
Result.Bridge :=
function(const sName: AnsiString; const tOptional: TObject): integer
begin
Result := fn(sName);
end;
end;
class operator fnBridge.Implicit(fn: fnB): fnBridge;
begin
Result.Bridge :=
function(const sName: AnsiString; const tOptional: TObject): integer
begin
Result := fn(sName, tOptional);
end;
end;
function A(const sName: AnsiString): integer;
begin Result := Length(sName) end;
function B(const sName: AnsiString; const tOptional: TObject): integer;
begin Result := Length(sName) - Length(tOptional.ClassName) end;
function Consumer (const Param1, Param2: integer; const Action: fnBridge): integer;
begin
Result := Param1 + Param2 * Action.Bridge('ABCDE', Application);
end;
....
ShowMessage( IntToStr( Consumer(10, 20, A) ));
ShowMessage( IntToStr( Consumer(10, 20, B) ));
PS:由于没有指定 Delphi 版本,这意味着任何 Delphi 版本的答案都适合。此方法应该适用于从 Delphi 2009 及更高版本开始的任何版本。
PPS:对具有捕获变量的函数的引用在内部实现为TInterfacedObject
后代。所以总的来说,这只是使用“高阶函数”的“策略模式”的简化案例
这是不可能的。为了使函数具有 type TFunctionPointer
,它必须声明两个参数。
默认参数仍然是参数。你TFunctionPointer
是一个有两个参数的函数。当您调用它并只提供一个参数时,编译器会在调用站点提供默认参数。所以两个参数仍然传递给函数。
对此进行扩展。考虑以下:
procedure Foo(Bar: Integer=666);
begin
end;
当您像这样调用过程时:
Foo();
看起来好像该过程没有参数。但事实并非如此。编译器将您的代码翻译成这样:
Foo(666);
结论是,如果您想允许接收具有不同数量参数的函数,则需要提供一种显式机制来接收这些不同的函数类型。例如:
procedure DoSomething(const Callback: TProc<string, TObject>); overload;
begin
Callback(str, obj);
end;
procedure DoSomething(const Callback: TProc<string>); overload;
begin
DoSomething(
procedure(arg1: string; arg2: TObject)
begin
Callback(arg1);
end
);
end;