9108

How to call object method for any object in my metaclass?

Question:

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.<br /> 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 <strong>without having to handle a list of TReqLogin, TReqSignIn types in the code (again)</strong>?

Answer1:

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.

Answer2:

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.

Recommend

  • Read a file in “chunks” using PHP
  • Leaflet z-index
  • Thread synchronization with syncwarp
  • auth.provider is not set to 'password' when user signs-in with email and password
  • How can I extend PHP DOMElement?
  • How can I run DataNucleus Bytecode Enhancer from SBT?
  • Jquery Knockout: ko.computed() vs classic function?
  • Trying to get the char code of ENTER key
  • Using Sax parsing to edit and write XML in VB6
  • Debug.DrawLine not showing in the GameView
  • How to get Eclipse Oxygen to run on Java 9
  • Installing Apache MyFaces 2 on WildFly 8.2.0
  • Yii2: Config params vs. const/define
  • Breeze - Deleted Items nav properties bug
  • NHibernate Validation Localization with S#arp Architecture
  • Using jQuery closest() method with class selector
  • How can I send an e-mail from a vbs script
  • Array.prototype.includes - not transformed with babel
  • javaw.exe and eclipse startup problems
  • swift auto completion not working in Xcode6-Beta
  • Accessing IRQ description array within a module and displaying action names
  • Bug in WPF DataGrid
  • Finding past revisions of files in StarTeam w/ .NET SDK / C#
  • TFS: Get latest causes slow project reloading
  • Javascript Callbacks with Object constructor
  • MySQL WHERE-condition in procedure ignored
  • ActionScript 2 vs ActionScript 3 performance
  • Statically linking a C++ library to a C# process using CLI or any other way
  • How to make Safari send if-modified-since header?
  • Web-crawler for facebook in python
  • Cannot Parse HTML Data Using Android / JSOUP
  • Rails 2: use form_for to build a form covering multiple objects of the same class
  • trying to dynamically update Highchart column chart but series undefined
  • Why can't I rebase on to an ancestor of source changesets if on a different branch?
  • C# - Getting references of reference
  • -fvisibility=hidden not passed by compiler for Debug builds
  • Getting Messege Twice Using IMvxMessenger
  • need help with bizarre java.net.HttpURLConnection behavior
  • Are Kotlin's Float, Int etc optimised to built-in types in the JVM? [duplicate]
  • java string with new operator and a literal