usar tipos que para metodos funciones funcion expresiones delegados delegado como anonimos anonimas delphi vcl anonymous-methods

delphi - tipos - Eventos de VCL con métodos anónimos: ¿qué piensas de esta implementación?



para que usar delegados c# (3)

Desde que aparecieron métodos anónimos en Delphi, quise usarlos en eventos de componentes de VCL. Obviamente, por compatibilidad con versiones anteriores, el VCL no se actualizó, por lo que pude hacer una implementación simple con algunas advertencias.

type TNotifyEventDispatcher = class(TComponent) protected FClosure: TProc<TObject>; procedure OnNotifyEvent(Sender: TObject); public class function Create(Owner: TComponent; Closure: TProc<TObject>): TNotifyEvent; overload; function Attach(Closure: TProc<TObject>): TNotifyEvent; end; implementation class function TNotifyEventDispatcher.Create(Owner: TComponent; Closure: TProc<TObject>): TNotifyEvent; begin Result := TNotifyEventDispatcher.Create(Owner).Attach(Closure) end; function TNotifyEventDispatcher.Attach(Closure: TProc<TObject>): TNotifyEvent; begin FClosure := Closure; Result := Self.OnNotifyEvent end; procedure TNotifyEventDispatcher.OnNotifyEvent(Sender: TObject); begin if Assigned(FClosure) then FClosure(Sender) end; end.

Y así es como se usa, por ejemplo:

procedure TForm1.FormCreate(Sender: TObject); begin Button1.OnClick := TNotifyEventDispatcher.Create(Self, procedure (Sender: TObject) begin Self.Caption := ''DONE!'' end) end;

Muy simple, creo, hay dos inconvenientes:

  • Tengo que crear un componente para administrar la vida útil del método anónimo (desperdicio un poco más de memoria, y es un poco más lento para la indirección, aún prefiero código más claro en mis aplicaciones)

  • Tengo que implementar una nueva clase (muy simple) para cada firma de evento. Este es un poco más complicado, aún así el VCL tiene firmas de eventos muy comunes, y para cada caso especial cuando creo la clase está hecho para siempre.

¿Qué piensas de esta implementación? Algo para hacerlo mejor?


Enfoque interesante.

(Descargo de responsabilidad: no se ha comprobado esto, pero es algo para investigar): puede que tenga que tener cuidado con lo que sucede al capturar el estado del método que "asigna" el método anónimo al evento. La captura puede ser una ventaja, pero también puede tener efectos secundarios que no desea. Si su método anónimo necesita información sobre el formulario en el momento en que se activa, puede terminar con información en el momento de su asignación. Actualización: aparentemente este no es el caso, vea el comentario de Stefan Glienke.

Realmente no necesitas diferentes clases. Con la sobrecarga puede crear diferentes class Create funciones que cada una tome una firma específica y devolver el controlador de eventos correspondiente y el compilador lo resolverá.

El tiempo de vida de gestión podría simplificarse si deriva de TInterfacedObject en lugar de TComponent. El recuento de referencias debería encargarse de destruir la instancia cuando el formulario ya no la utiliza. Actualización : esto requiere mantener una referencia a la instancia en algún lugar del formulario, o el recuento no ayudará ya que la instancia se liberará inmediatamente después de asignar el evento de notificación. Puede agregar un parámetro adicional en la clase Crear funciones a la que le pase un método que la instancia puede usar para agregarse a alguna lista del formulario.

Nota al margen: en general, tengo que estar de acuerdo con David en su comentario sobre la pregunta: parece un montón de trabajo con el "único propósito" de usar métodos anónimos ...


Puede hacer que TNotifyEventDispatcher sea ​​una subclase de TInterfacedObject para que no tenga que preocuparse por liberarla.

Pero para ser más pragmático, uno usaría la asignación tradicional de eventos que requiere menos líneas de código y es compatible con el IDE.


Puedes echar un vistazo a mi implementación de eventos de multidifusión en DSharp .

Entonces puedes escribir código como este:

function NotifyEvent(Owner: TComponent; Delegates: array of TProc<TObject>): TNotifyEvent; overload; begin Result := TEventHandler<TNotifyEvent>.Create<TProc<TObject>>(Owner, Delegates).Invoke; end; function NotifyEvent(Owner: TComponent; Delegate: TProc<TObject>): TNotifyEvent; overload; begin Result := NotifyEvent(Owner, [Delegate]); end; procedure TForm1.FormCreate(Sender: TObject); begin Button1.OnClick := NotifyEvent(Button1, [ procedure(Sender: TObject) begin Caption := ''Started''; end, procedure(Sender: TObject) begin if MessageDlg(''Continue?'', mtConfirmation, mbYesNo, 0) <> mrYes then begin Caption := ''Canceled''; Abort; end; end, procedure(Sender: TObject) begin Caption := ''Finished''; end]); end;