Search code examples
delphidelphi-xe2

Delphi passing Types in parameters


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 ?


Solution

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