Jump to content
dormky

Is it possible to cast an anonymous procedure to a procedure of object ?

Recommended Posts

In Data.DB, the dataset events are defined as

TDataSetNotifyEvent = procedure(DataSet: TDataSet) of object;

This means that such code as

MyTableTest.BeforeDelete := procedure (d: TDataSet) begin LogTableOperation('MyTableTestBeforeDelete'); end;

not valid. Is there anyway of casting this ? I'd rather not define a procedure in my data module for every event of every table...

Share this post


Link to post
24 minutes ago, dormky said:

Is there anyway of casting this ?

No, they are fundamentally different things in terms of implementation. 

Share this post


Link to post

This is documented behavior:

https://docwiki.embarcadero.com/RADStudio/en/Anonymous_Methods_in_Delphi

Quote

you cannot assign an anonymous method to a regular method pointer. Method references are managed types, but method pointers are unmanaged types. Thus, for type-safety reasons, assigning method references to method pointers is not supported. For instance, events are method pointer-valued properties, so you cannot use an anonymous method for an event.

 

  • Like 1

Share this post


Link to post
On 1/20/2025 at 8:19 AM, dormky said:

I'd rather not define a procedure in my data module for every event of every table...

If several tables will use events with identical functionality, such as logging, you can have a single event assigned to multiple tables:

 

procedure TForm1.AllTablesBeforeDelete(DataSet: TDataSet);
begin
  LogTableOperation(DataSet.Name + 'BeforeDelete');
end;
  MyTable1Test.BeforeDelete := AllTablesBeforeDelete;
  MyTable2Test.BeforeDelete := AllTablesBeforeDelete;
  MyTable3Test.BeforeDelete := AllTablesBeforeDelete;

Or assign the event handler to each table using the object inspector.

Share this post


Link to post
18 hours ago, JonRobertson said:

If several tables will use events with identical functionality, such as logging, you can have a single event assigned to multiple tables:

 


procedure TForm1.AllTablesBeforeDelete(DataSet: TDataSet);
begin
  LogTableOperation(DataSet.Name + 'BeforeDelete');
end;

  MyTable1Test.BeforeDelete := AllTablesBeforeDelete;
  MyTable2Test.BeforeDelete := AllTablesBeforeDelete;
  MyTable3Test.BeforeDelete := AllTablesBeforeDelete;

Or assign the event handler to each table using the object inspector.

That's what I ended up with yes

Share this post


Link to post

You can't just convert it, but you can make same behaviour

type
  TDataSetAnonimouseEvent = reference to procedure(DataSet: TDataSet);

  TForm3 = class(TForm)
    FDQuery1: TFDQuery;
    bntAddNewEvent: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure bntAddNewEventClick(Sender: TObject);
  private
    { Private declarations }
    FEventLinks : TDictionary<TComponent, TDataSetAnonimouseEvent>;
  public
    { Public declarations }
    procedure AllTablesBeforeDelete(DataSet: TDataSet);
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

procedure TForm3.AllTablesBeforeDelete(DataSet: TDataSet);
begin
  //check if we have anonymous event for this component
  if FEventLinks.ContainsKey(DataSet) then
  begin
    //call anonymous event
    FEventLinks[DataSet](DataSet);
  end;
end;

procedure TForm3.bntAddNewEventClick(Sender: TObject);
begin
  //link anonymous event to specific component
  FEventLinks.Add(FDQuery1,
                  procedure(DataSet: TDataSet)
                  begin
                    ShowMessage('Anonimouse event!');
                  end
                 );
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
  FEventLinks := TDictionary<TComponent, TDataSetAnonimouseEvent>.Create;

  FDQuery1.BeforeDelete := AllTablesBeforeDelete;
end;

procedure TForm3.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FEventLinks);
end;

 

Share this post


Link to post

Hmm..

 

or you make it with a simple helper:

 

type
  TMakeObjectFunc = class
  public
    class procedure Log(d: TDataSet);
  end;

{ TMakeObjectFunc }

class procedure TMakeObjectFunc.Log(d: TDataSet);
begin
  LogTableOperation('MyTableTestBeforeDel?ete');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  MyTableTest.BeforeDelete := TMakeObjectFunc.Log;
end;

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×