Frage

I have basically this object structure:

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
     ); 

Now I do:

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

and I want to call

lRequestClass.FillWithTemplateData;

in order to execute TReqLogin.FillWithTemplateData when lWebAct = ttlogin etc.
But it won't compile: E2706 This form of method call only allowed for class methods.

I do understand the reason (the text of the compiler message) but how can I fix this so that TReqLogin.FillWithTemplateData gets executed when lWebAct=ttlogin etc without having to handle a list of TReqLogin, TReqSignIn types in the code (again)?

War es hilfreich?

Lösung

lRequestClass is a class reference. You can call class methods on it, but not instance methods. And FillWithTemplateData is an instance method.

You need to have an instance to call an instance method. So instantiate one:

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

If you develop the classes so that they need to perform work in their constructors then you must introduce a virtual constructor to TReqBase. And override that in derived classes. That's the only way that you can make sure that the derived constructor runs when you are instantiating from a class reference.

Perhaps your system requires instances to be instantiated in some other way, I cannot tell from here. No matter what, however you instantiate then, you need an instance to call an instance method.

Andere Tipps

Have you tried using an Interface Reference instead?

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.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top