如何为我的元类中的任何对象调用对象方法?

时间:2013-08-08 11:59:02

标签: delphi delphi-xe2 metaclass

我基本上有这个对象结构:

TJSONStructure = class(TObject);

TReqBase = class(TJSONStructure)
private
   token: Int64;
public
   procedure FillWithTemplateData; virtual;
end;

TReqLogin = class(TReqBase)
private
   username,
   password: String;
   module  : Integer;
public
   procedure FillWithTemplateData; override;
end;

procedure TReqBase.FillWithTemplateData;
begin
   token := ...;
end;

procedure TReqLogin.FillWithTemplateData;
begin
   inherited;
   username := ...;
   password := ...;
   module   := ...;
end;

type
   TWebAct = (ttlogin,
              ttsignin);

TReqClass = class of TReqBase;

const
   cWebActStructures: Array[TWebAct] of
   record
      RequestClass : TReqClass;
   end
   = (
      { ttlogin  } (RequestClass: TReqLogin;),
      { ttsignin } (RequestClass: TReqSignIn;)     // Not in definitions above
     ); 

现在我做了:

var
   lWebAct       : TWebAct;
   lRequestClass : TReqClass;
begin
   for lWebAct := Low(TWebAct) to High(TWebAct) do
   begin
      lRequestClass := cWebActStructures[lWebAct].RequestClass;

我想打电话

lRequestClass.FillWithTemplateData;

为了在lWebAct = TReqLogin.FillWithTemplateData等时执行ttlogin 但它不会编译:{{1​​}}

我确实理解了原因(编译器消息的文本),但是如何解决这个问题,以便在lWebAct = ttlogin等时执行TReqLogin.FillWithTemplateData,而不必处理TReqLogin,TReqSignIn类型中的TReqSinIn类型代码(再次)

2 个答案:

答案 0 :(得分:2)

lRequestClass是一个类引用。您可以在其上调用class方法,但不能调用实例方法。 FillWithTemplateData是一种实例方法。

您需要有一个实例来调用实例方法。所以实例化一个:

var 
  req: TReqBase; 
....
req := lRequestClass.Create; 
try
  req.FillWithTemplateData;
  ...
finally
  req.Free;
end;

如果您开发类以便他们需要在构造函数中执行工作,那么您必须向TReqBase引入虚拟构造函数。并在派生类中覆盖它。这是在从类引用实例化时确保派生构造函数运行的唯一方法。

也许你的系统需要以其他方式实例化实例,我不能从这里说出来。无论如何,无论如何实例化,都需要一个实例来调用实例方法。

答案 1 :(得分:1)

您是否尝试过使用接口参考?

type

  IReqBase = Interface(IInterface)
  ['{B71BD1C3-CE4C-438A-8090-DA6AACF0B3C4}']
    procedure FillWithTemplateData;
  end;

  type
   TWebAct = (ttlogin,
              ttsignin);

  TForm59 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    CheckBox1: TCheckBox;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
    FReqList: Array of IReqBase;
    procedure CreateBaseList;
    procedure ClearBaseList;
  public
    { Public declarations }
  end;

  TJSONStructure = class(TInterfacedObject);



  TReqBaseClass = class of TReqBase;

  TReqBase = class(TJSONStructure, IReqBase)
  private
     token: Int64;
  protected
    class function ReqClass: TReqBaseClass; virtual; abstract;
  public
     Constructor Create; virtual;
     procedure FillWithTemplateData; virtual;
     class function ReqBase: IReqBase;
  end;

  TReqLogin = class(TReqBase)
  private
    Fusername,
    Fpassword: String;
    Fmodule  : Integer;
  protected
    class function ReqClass: TReqBaseClass; override;
  public
     Constructor Create; override;
     Destructor Destroy; override;
     procedure FillWithTemplateData; override;
  end;

  TReqSignIn = class(TReqBase)
  private
    Fusername,
    Fpassword: String;
    Fmodule  : Integer;
  protected
    class function ReqClass: TReqBaseClass; override;
  public
     Constructor Create; override;
     Destructor Destroy; override;

     procedure FillWithTemplateData; override;
  end;

var
  Form59: TForm59;

implementation

{$R *.dfm}

procedure TForm59.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Clear;
  IReqBase(FReqList[integer(CheckBox1.Checked)]).FillWithTemplateData;
end;

procedure TForm59.Button2Click(Sender: TObject);
begin
  CreateBaseList;
end;

procedure TForm59.Button3Click(Sender: TObject);
begin
  if CheckBox1.Checked then
    TReqSignIn.ReqBase.FillWithTemplateData
  else
    TReqLogin.ReqBase.FillWithTemplateData;
end;

procedure TForm59.ClearBaseList;
begin
  SetLength(FReqList, 0);
end;

procedure TForm59.CreateBaseList;
begin
  if High(FReqList) = Ord(High(TWebAct)) +1 then
    ClearBaseList;

  SetLength(FReqList, Ord(High(TWebAct)) + 1 );
  FReqList[ord(ttlogin)] := TReqLogin.ReqBase;
  FReqList[ord(ttsignin)] := TReqSignIn.ReqBase;
end;

procedure TForm59.FormCreate(Sender: TObject);
begin
  CreateBaseList;
end;

procedure TForm59.FormDestroy(Sender: TObject);
begin
  ClearBaseList;
end;

{ TReqLogin }

constructor TReqLogin.Create;
begin
  inherited;
  FUserName := 'Rick';
  FPassword := 'Test';
  Fmodule := 100;
end;

destructor TReqLogin.Destroy;
begin
  Form59.Memo1.Lines.Add('Destroyed: ' +ClassName);
  inherited;
end;

procedure TReqLogin.FillWithTemplateData;
begin
  inherited;
  Form59.Memo1.Lines.Add(Fusername);
  Form59.Memo1.Lines.Add(FPassword);
  Form59.Memo1.Lines.Add(IntToStr(FModule));
end;

class function TReqLogin.ReqClass: TReqBaseClass;
begin
  Result := TReqLogin;
end;

{ TReqBase }

constructor TReqBase.Create;
begin
  inherited;
  Token := -1;
end;

procedure TReqBase.FillWithTemplateData;
begin
  Form59.Memo1.Lines.Add(IntToStr(Token));
end;

class function TReqBase.ReqBase: IReqBase;
begin
  Result := ReqClass.Create;
end;

{ TReqSignIn }

constructor TReqSignIn.Create;
begin
  inherited;
  FUserName := 'Peterson';
  FPassword := 'TestPW';
  Fmodule := 101;
end;

destructor TReqSignIn.Destroy;
begin
  Form59.Memo1.Lines.Add('Destroyed: ' +ClassName);
  inherited;
end;

procedure TReqSignIn.FillWithTemplateData;
begin
  inherited;
  Form59.Memo1.Lines.Add(Fusername);
  Form59.Memo1.Lines.Add(FPassword);
  Form59.Memo1.Lines.Add(IntToStr(FModule));
end;

class function TReqSignIn.ReqClass: TReqBaseClass;
begin
  Result := TReqSignIn;
end;

end.