gpt4 book ai didi

delphi - 在 Delphi 2007 中鸭子类型(duck typing)?

转载 作者:行者123 更新时间:2023-12-03 14:39:47 33 4
gpt4 key购买 nike

问题:

有没有办法使用 Delphi 2007 进行鸭子类型(duck typing)(即没有泛型和高级 Rtti 功能)?

<小时/>

Delphi 2010 及以后版本的 Duck 类型资源:

上次编辑:

我深入研究了上面列出的资源,并研究了此处发布的每个答案。

我最终完善了我的要求并制作了 follow up post对于这个问题。

最佳答案

在 ObjAuto.pas 和可调用变体类型的帮助下,这应该是可能的(用 XE 编写,但也应该在 Delphi 7 或更低版本中运行):

unit DuckTyping;

interface

function Duck(Instance: TObject): Variant;

implementation

uses
ObjAuto,
SysUtils,
TypInfo,
Variants;

type
TDuckVarData = packed record
VType: TVarType;
Reserved1, Reserved2, Reserved3: Word;
VDuck: TObject;
Reserved4: LongWord;
end;

TDuckVariantType = class(TPublishableVariantType)
protected
function GetInstance(const V: TVarData): TObject; override;
public
procedure Clear(var V: TVarData); override;
procedure Copy(var Dest: TVarData; const Source: TVarData;
const Indirect: Boolean); override;
function DoFunction(var Dest: TVarData; const V: TVarData;
const Name: string; const Arguments: TVarDataArray): Boolean; override;
end;

var
DuckVariantType: TDuckVariantType;

{ TDuckVariantType }

procedure TDuckVariantType.Clear(var V: TVarData);
begin
V.VType := varEmpty;
TDuckVarData(V).VDuck := nil;
end;

procedure TDuckVariantType.Copy(var Dest: TVarData; const Source: TVarData;
const Indirect: Boolean);
begin
if Indirect and VarDataIsByRef(Source) then
VarDataCopyNoInd(Dest, Source)
else
begin
with TDuckVarData(Dest) do
begin
VType := VarType;
VDuck := TDuckVarData(Source).VDuck;
end;
end;
end;

function TDuckVariantType.DoFunction(var Dest: TVarData; const V: TVarData;
const Name: string; const Arguments: TVarDataArray): Boolean;
var
instance: TObject;
methodInfo: PMethodInfoHeader;
paramIndexes: array of Integer;
params: array of Variant;
i: Integer;
ReturnValue: Variant;
begin
instance := GetInstance(V);
methodInfo := GetMethodInfo(instance, ShortString(Name));
Result := Assigned(methodInfo);
if Result then
begin
SetLength(paramIndexes, Length(Arguments));
SetLength(params, Length(Arguments));
for i := Low(Arguments) to High(Arguments) do
begin
paramIndexes[i] := i + 1;
params[i] := Variant(Arguments[i]);
end;

ReturnValue := ObjectInvoke(instance, methodInfo, paramIndexes, params);
if not VarIsEmpty(ReturnValue) then
VarCopy(Variant(Dest), ReturnValue);
end
else
begin
VarClear(Variant(Dest));
end;
end;

function TDuckVariantType.GetInstance(const V: TVarData): TObject;
begin
Result := TDuckVarData(V).VDuck;
end;

function Duck(Instance: TObject): Variant;
begin
TDuckVarData(Result).VType := DuckVariantType.VarType;
TDuckVarData(Result).VDuck := Instance;
end;

initialization
DuckVariantType := TDuckVariantType.Create;

finalization
FreeAndNil(DuckVariantType);

end.

您可以像这样简单地使用它:

type
{$METHODINFO ON}
TDuck = class
public // works in XE, not sure if it needs to be published in older versions
procedure Quack;
end;

procedure TDuck.Quack;
begin
ShowMessage('Quack');
end;

procedure DoSomething(D: Variant);
begin
D.Quack;
end;

var
d: TDuck;
begin
d := TDuck.Create;
try
DoSomething(Duck(d));
finally
d.Free;
end;
end;

关于delphi - 在 Delphi 2007 中鸭子类型(duck typing)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9497708/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com