Delphi passing Types in parameters

2k views Asked by At

an example, I need to do this to solve a problem in a framework I am developing :

//Unit2 :
    procedure A(aForm : TForm; AClassType: TFormClass); 
    begin 
       ShowMessage (AClassType(aForm).edtUser.text);
    end; 

    ...

//Unit1 :

    Uses Unit2;

    begin
       form1 := TForm1.Create;
       Try  
          A(form1, TForm1); 
       Finally
          form1.Free;
       End;
    end;

The compiler does not accept this line:

AClassType (aform).edtUser.text

One solution would be to use:

Uses
    UnitofTForm1;

The procedure (aform: TForm; AClassType: TForm1);
begin
    ShowMessage (AClassType (aform).edtUser.text);
end;

But I can not do so because they are giving circular reference and I need some decoupling in my framework

Is there any way to make typecast passing as parameter the type of form or is there another way to do this ?

1

There are 1 answers

3
Remy Lebeau On BEST ANSWER

What you are asking for can be done by either:

  1. deriving the various Form classes from a common base class that exposes the field you want to access:

    procedure A(aForm : TBaseForm); 
    begin 
      ShowMessage(aForm.edtUser.Text);
    end; 
    

    type
      TBaseForm = class(TForm)
        edtUser: TEdit;
        ...
      end;
    
      TDerivedForm = class(TBaseForm)
        ...
      end;
    
    ...
    
    frm := TDerivedForm.Create;
    try  
      A(frm); 
    finally
      frm.Free;
    end;
    
  2. or, use Generics:

    type
      TBaseForm = class(TForm)
        edtUser: TEdit;
        ...
      end;
    
      TMyClass = class
        class procedure A<T: TBaseForm>(aForm : T); 
      end;
    
    class procedure TMyClass.A<T>(aForm : T); 
    begin 
       ShowMessage(aForm.edtUser.Text);
    end; 
    

    frm := TDerivedForm.Create;
    try  
      A<TDerivedForm>(frm); 
    finally
      frm.Free;
    end;
    
  3. if a common base class is not possible, use an interface instead:

    type
      IMyFormAccess = interface
        function GetUserText: string;
      end;
    
    procedure A(aForm : IMyFormAccess); 
    begin 
      ShowMessage(aForm.GetUserText);
    end; 
    

    type
      TForm1 = class(TForm, IMyFormAccess)
        ...
        function GetUserText: string;
        ...
      end;
    
    function TForm1.GetUserText: string;
    begin
      Result := edtUser.Text;
    end;
    
    ...
    
    frm := TForm1.Create;
    try  
      A(frm as IMyFormAccess);
    finally
      frm.Free;
    end;
    
  4. or, use legacy RTTI (only works with published properties):

    uses
      TypInfo;
    
    procedure A(aForm : TForm); 
    var
      Edt: TEdit;
    begin 
      Edt := TEdit(GetObjectProp(aForm, 'edtUser', TEdit));
      if Edt <> nil then
        ShowMessage(Edt.Text);
    end; 
    

    frm := TForm1.Create;
    try  
      A(frm);
    finally
      frm.Free;
    end;
    
  5. or, use extended RTTI (works with all fields and visibility):

    uses
      System.Rtti;
    
    procedure A(aForm : TForm); 
    var
      Ctx: TRttiContext;
      Fld: TRttiField;
      Value: TValue;
      Edt: TEdit;
    begin 
      Fld := Ctx.GetType(aForm.ClassType).GetField('edtUser');
      if Fld <> nil then
      begin
        Value := Fld.GetValue(aForm);
        if (not Value.IsEmpty) and Value.IsObject then
        begin
          Edt := Value.AsObject as TEdit;
          ShowMessage(Edt.Text);
        end;
      end;
    end;
    

    frm := TForm1.Create;
    try  
      A(frm);
    finally
      frm.Free;
    end;