Delphi 2007中的Duck键入(续)?

Delphi 2007中的Duck键入(续)?,delphi,delphi-2007,duck-typing,Delphi,Delphi 2007,Duck Typing,这是对此的后续行动 我根据贴出的被接受的答案改进了我的要求 My*.dpr文件: program DuckD11; {$APPTYPE CONSOLE} uses SysUtils, uDuckTyping in 'uDuckTyping.pas', uBirds in 'uBirds.pas'; procedure DoSomething(AObject: TObject); begin Duck(AObject).Quack; end; var Bird: TBi

这是对此的后续行动

我根据贴出的被接受的答案改进了我的要求

My*.dpr文件:

program DuckD11;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  uDuckTyping in 'uDuckTyping.pas',
  uBirds in 'uBirds.pas';

procedure DoSomething(AObject: TObject);
begin
  Duck(AObject).Quack;
end;

var
  Bird: TBird;
  Ganagana: TGanagana;
  Canard: TCanard;
begin
  Writeln('Duck typing :');
  Writeln;

  Bird := TBird.Create('Bird');
  try
    DoSomething(Bird);
  finally
    Bird.Free;
  end;

  Ganagana := TGanagana.Create;
  try
    DoSomething(Ganagana);
  finally
    Ganagana.Free;
  end;

  Canard := TCanard.Create;
  try
    DoSomething(Canard);
  finally
    Canard.Free;
  end;

  Readln;
end.
unit uBirds;

interface

uses
  SysUtils;

type
  {$METHODINFO ON}
  TBird = class
  private
    FName: string;
  public
    constructor Create(AName: string);
    procedure Quack;
  end;

  TGanagana = class
  private
    const cName = 'Ganagana';
  public
    procedure Quack;
  end;

  TCanard = class
  private
    const cName = 'Canard';
  public
    procedure Quack;
  end;

  {$METHODINFO OFF}

implementation

{ TBird }

constructor TBird.Create(AName: string);
begin
  FName := AName;
end;

procedure TBird.Quack;
begin
  Writeln(Format('  %s->Quack',[Self.FName]));
end;

{ TGanagana }

procedure TGanagana.Quack;
begin
  Writeln(Format('  %s=>Quack',[Self.cName]));
end;

{ TCanard }

procedure TCanard.Quack;
begin
  Writeln(Format('  %s::Quack',[Self.cName]));
end;

end.
unit uDuckTyping;

interface

type
  IDuck = interface
    ['{41780389-7158-49F7-AAA5-A4ED5AE2699E}']
    procedure Quack;
  end;

function Duck(AObject: TObject): IDuck;

implementation

uses
  ObjAuto;

type
  TDuckObject = class(TInterfacedObject, IDuck)
  private
    FObj: TObject;

    // ???

  protected
      procedure Quack;
  public
    constructor Create(AObject: TObject);
  end;

function Duck(AObject: TObject): IDuck;
begin
  Result := TDuckObject.Create(AObject);
end;

{ TDuckObject }

constructor TDuckObject.Create(AObject: TObject);
begin
  FObj := AObject;

  // ???
end;

procedure TDuckObject.Quack;
begin
  // ???
end;

end.
uBirds.pas列表:

program DuckD11;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  uDuckTyping in 'uDuckTyping.pas',
  uBirds in 'uBirds.pas';

procedure DoSomething(AObject: TObject);
begin
  Duck(AObject).Quack;
end;

var
  Bird: TBird;
  Ganagana: TGanagana;
  Canard: TCanard;
begin
  Writeln('Duck typing :');
  Writeln;

  Bird := TBird.Create('Bird');
  try
    DoSomething(Bird);
  finally
    Bird.Free;
  end;

  Ganagana := TGanagana.Create;
  try
    DoSomething(Ganagana);
  finally
    Ganagana.Free;
  end;

  Canard := TCanard.Create;
  try
    DoSomething(Canard);
  finally
    Canard.Free;
  end;

  Readln;
end.
unit uBirds;

interface

uses
  SysUtils;

type
  {$METHODINFO ON}
  TBird = class
  private
    FName: string;
  public
    constructor Create(AName: string);
    procedure Quack;
  end;

  TGanagana = class
  private
    const cName = 'Ganagana';
  public
    procedure Quack;
  end;

  TCanard = class
  private
    const cName = 'Canard';
  public
    procedure Quack;
  end;

  {$METHODINFO OFF}

implementation

{ TBird }

constructor TBird.Create(AName: string);
begin
  FName := AName;
end;

procedure TBird.Quack;
begin
  Writeln(Format('  %s->Quack',[Self.FName]));
end;

{ TGanagana }

procedure TGanagana.Quack;
begin
  Writeln(Format('  %s=>Quack',[Self.cName]));
end;

{ TCanard }

procedure TCanard.Quack;
begin
  Writeln(Format('  %s::Quack',[Self.cName]));
end;

end.
unit uDuckTyping;

interface

type
  IDuck = interface
    ['{41780389-7158-49F7-AAA5-A4ED5AE2699E}']
    procedure Quack;
  end;

function Duck(AObject: TObject): IDuck;

implementation

uses
  ObjAuto;

type
  TDuckObject = class(TInterfacedObject, IDuck)
  private
    FObj: TObject;

    // ???

  protected
      procedure Quack;
  public
    constructor Create(AObject: TObject);
  end;

function Duck(AObject: TObject): IDuck;
begin
  Result := TDuckObject.Create(AObject);
end;

{ TDuckObject }

constructor TDuckObject.Create(AObject: TObject);
begin
  FObj := AObject;

  // ???
end;

procedure TDuckObject.Quack;
begin
  // ???
end;

end.
我尝试编码uDuckTyping.pas:

program DuckD11;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  uDuckTyping in 'uDuckTyping.pas',
  uBirds in 'uBirds.pas';

procedure DoSomething(AObject: TObject);
begin
  Duck(AObject).Quack;
end;

var
  Bird: TBird;
  Ganagana: TGanagana;
  Canard: TCanard;
begin
  Writeln('Duck typing :');
  Writeln;

  Bird := TBird.Create('Bird');
  try
    DoSomething(Bird);
  finally
    Bird.Free;
  end;

  Ganagana := TGanagana.Create;
  try
    DoSomething(Ganagana);
  finally
    Ganagana.Free;
  end;

  Canard := TCanard.Create;
  try
    DoSomething(Canard);
  finally
    Canard.Free;
  end;

  Readln;
end.
unit uBirds;

interface

uses
  SysUtils;

type
  {$METHODINFO ON}
  TBird = class
  private
    FName: string;
  public
    constructor Create(AName: string);
    procedure Quack;
  end;

  TGanagana = class
  private
    const cName = 'Ganagana';
  public
    procedure Quack;
  end;

  TCanard = class
  private
    const cName = 'Canard';
  public
    procedure Quack;
  end;

  {$METHODINFO OFF}

implementation

{ TBird }

constructor TBird.Create(AName: string);
begin
  FName := AName;
end;

procedure TBird.Quack;
begin
  Writeln(Format('  %s->Quack',[Self.FName]));
end;

{ TGanagana }

procedure TGanagana.Quack;
begin
  Writeln(Format('  %s=>Quack',[Self.cName]));
end;

{ TCanard }

procedure TCanard.Quack;
begin
  Writeln(Format('  %s::Quack',[Self.cName]));
end;

end.
unit uDuckTyping;

interface

type
  IDuck = interface
    ['{41780389-7158-49F7-AAA5-A4ED5AE2699E}']
    procedure Quack;
  end;

function Duck(AObject: TObject): IDuck;

implementation

uses
  ObjAuto;

type
  TDuckObject = class(TInterfacedObject, IDuck)
  private
    FObj: TObject;

    // ???

  protected
      procedure Quack;
  public
    constructor Create(AObject: TObject);
  end;

function Duck(AObject: TObject): IDuck;
begin
  Result := TDuckObject.Create(AObject);
end;

{ TDuckObject }

constructor TDuckObject.Create(AObject: TObject);
begin
  FObj := AObject;

  // ???
end;

procedure TDuckObject.Quack;
begin
  // ???
end;

end.
我的问题:

program DuckD11;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  uDuckTyping in 'uDuckTyping.pas',
  uBirds in 'uBirds.pas';

procedure DoSomething(AObject: TObject);
begin
  Duck(AObject).Quack;
end;

var
  Bird: TBird;
  Ganagana: TGanagana;
  Canard: TCanard;
begin
  Writeln('Duck typing :');
  Writeln;

  Bird := TBird.Create('Bird');
  try
    DoSomething(Bird);
  finally
    Bird.Free;
  end;

  Ganagana := TGanagana.Create;
  try
    DoSomething(Ganagana);
  finally
    Ganagana.Free;
  end;

  Canard := TCanard.Create;
  try
    DoSomething(Canard);
  finally
    Canard.Free;
  end;

  Readln;
end.
unit uBirds;

interface

uses
  SysUtils;

type
  {$METHODINFO ON}
  TBird = class
  private
    FName: string;
  public
    constructor Create(AName: string);
    procedure Quack;
  end;

  TGanagana = class
  private
    const cName = 'Ganagana';
  public
    procedure Quack;
  end;

  TCanard = class
  private
    const cName = 'Canard';
  public
    procedure Quack;
  end;

  {$METHODINFO OFF}

implementation

{ TBird }

constructor TBird.Create(AName: string);
begin
  FName := AName;
end;

procedure TBird.Quack;
begin
  Writeln(Format('  %s->Quack',[Self.FName]));
end;

{ TGanagana }

procedure TGanagana.Quack;
begin
  Writeln(Format('  %s=>Quack',[Self.cName]));
end;

{ TCanard }

procedure TCanard.Quack;
begin
  Writeln(Format('  %s::Quack',[Self.cName]));
end;

end.
unit uDuckTyping;

interface

type
  IDuck = interface
    ['{41780389-7158-49F7-AAA5-A4ED5AE2699E}']
    procedure Quack;
  end;

function Duck(AObject: TObject): IDuck;

implementation

uses
  ObjAuto;

type
  TDuckObject = class(TInterfacedObject, IDuck)
  private
    FObj: TObject;

    // ???

  protected
      procedure Quack;
  public
    constructor Create(AObject: TObject);
  end;

function Duck(AObject: TObject): IDuck;
begin
  Result := TDuckObject.Create(AObject);
end;

{ TDuckObject }

constructor TDuckObject.Create(AObject: TObject);
begin
  FObj := AObject;

  // ???
end;

procedure TDuckObject.Quack;
begin
  // ???
end;

end.
我想用

  • ObjAuto.GetMethodInfo以确定是否存在包装的江湖郎中方法
  • ObjAuto.ObjectInvoke调用包装的江湖郎中方法

如何完成代码?

经过多次尝试后,我终于让代码正常工作:

uDucktyping.pas单元中的修改:

program DuckD11;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  uDuckTyping in 'uDuckTyping.pas',
  uBirds in 'uBirds.pas';

procedure DoSomething(AObject: TObject);
begin
  Duck(AObject).Quack;
end;

var
  Bird: TBird;
  Ganagana: TGanagana;
  Canard: TCanard;
begin
  Writeln('Duck typing :');
  Writeln;

  Bird := TBird.Create('Bird');
  try
    DoSomething(Bird);
  finally
    Bird.Free;
  end;

  Ganagana := TGanagana.Create;
  try
    DoSomething(Ganagana);
  finally
    Ganagana.Free;
  end;

  Canard := TCanard.Create;
  try
    DoSomething(Canard);
  finally
    Canard.Free;
  end;

  Readln;
end.
unit uBirds;

interface

uses
  SysUtils;

type
  {$METHODINFO ON}
  TBird = class
  private
    FName: string;
  public
    constructor Create(AName: string);
    procedure Quack;
  end;

  TGanagana = class
  private
    const cName = 'Ganagana';
  public
    procedure Quack;
  end;

  TCanard = class
  private
    const cName = 'Canard';
  public
    procedure Quack;
  end;

  {$METHODINFO OFF}

implementation

{ TBird }

constructor TBird.Create(AName: string);
begin
  FName := AName;
end;

procedure TBird.Quack;
begin
  Writeln(Format('  %s->Quack',[Self.FName]));
end;

{ TGanagana }

procedure TGanagana.Quack;
begin
  Writeln(Format('  %s=>Quack',[Self.cName]));
end;

{ TCanard }

procedure TCanard.Quack;
begin
  Writeln(Format('  %s::Quack',[Self.cName]));
end;

end.
unit uDuckTyping;

interface

type
  IDuck = interface
    ['{41780389-7158-49F7-AAA5-A4ED5AE2699E}']
    procedure Quack;
  end;

function Duck(AObject: TObject): IDuck;

implementation

uses
  ObjAuto;

type
  TDuckObject = class(TInterfacedObject, IDuck)
  private
    FObj: TObject;

    // ???

  protected
      procedure Quack;
  public
    constructor Create(AObject: TObject);
  end;

function Duck(AObject: TObject): IDuck;
begin
  Result := TDuckObject.Create(AObject);
end;

{ TDuckObject }

constructor TDuckObject.Create(AObject: TObject);
begin
  FObj := AObject;

  // ???
end;

procedure TDuckObject.Quack;
begin
  // ???
end;

end.

在类定义中添加为私有的字段

FQuackPMethodInfo: PMethodeInfoHeader;
FParamIndexes: array of Integer;
FParams: array of Variant;

TDuckObject.Create实现中初始化FQuackPMethodInfo

FQuackPMethodInfo := GetMethodInfo(AObject, ShortString('Quack'));
if Assigned(FQuackPMethodInfo) then
  ObjectInvoke(FObj, FQuackPMethodInfo, FParamIndexes, FParams);
在FObj初始化语句之后追加


TDuckObject.Quack实现中调用“Quack”

FQuackPMethodInfo := GetMethodInfo(AObject, ShortString('Quack'));
if Assigned(FQuackPMethodInfo) then
  ObjectInvoke(FObj, FQuackPMethodInfo, FParamIndexes, FParams);

你为什么不直接调用它,捕捉异常?我不得不笑,你要求使用动态键入,而现在你却不愿意使用它,并且用你唯一能做的方式(异常处理)处理后果。我只是尝试复制
Duck-typing
,就像Daniele Teti在DORM(DORM.utils.TDuckTypedList)中用D2007做的那样。他将trtti方法与Invoke结合使用(目标是Delphi 2010以后的产品)分为两步:1)提取方法Rtti并将其存储在某处,最终在缺少方法或签名不匹配的情况下引发异常2)稍后使用存储的Rtti调用具有适当参数的方法。我猜您在Delphi中进行基于IDispatch的处理,它与Delphi 2010以后的TrtiMethod存储是同态的。我认为您尝试做的与XE2中引入的TVirtualInterface类似。虽然对于这个简单的无参数方法来说很容易,但当您有多个带参数的方法时,这可能会变得更复杂。虽然duck类型基本上是适配器模式,但您所做的更像是一个特定的适配器(受制于IDuck)。@Stefan Glienke:您是对的,我的示例非常集中且有限:我必须研究如何正确处理带有参数的处理方法,并最终返回值。顺便说一句,你提到TVirtualInterface,我知道你已经做了一个备份,如果你能考虑一下这个问题吗?”Stefan Glienke:我仔细检查了代码> d夏普.Cual.PuxIsPaS/代码>,并非常欣赏它。对TVirtualInterface非常有能力。