delphi - runtimebinderexception - tipos de delegados en c#
¿Alguien puede explicarme los métodos anónimos? (7)
Estoy respondiendo mi propia pregunta, pero encontré una buena explicación de los métodos anónimos aquí. ¿Puede tu lenguaje de programación hacer esto?
Delphi 2009, entre algunas cosas interesantes, también acaba de obtener métodos anónimos. He visto los ejemplos y las publicaciones del blog sobre métodos anónimos, pero aún no los obtengo. ¿Alguien puede explicar por qué debería estar emocionado?
La gente ya me ha proporcionado el código, así que solo enumeraré algunos lugares donde pueden ser útiles.
Digamos que tiene un código GUI. Normalmente, para algo como el manejador onclick de un botón, debe proporcionar una función que se invocará cuando se haga clic en ese botón. Sin embargo, digamos que toda esa función tiene que hacer es algo simple como abrir un cuadro de mensaje o establecer un campo en alguna parte. Digamos que tiene docenas de estos botones en todo su código. Sin funciones anónimas, tendrá que tener toneladas de funciones llamadas "OnButton1Click", "OnExitButtonClick", etc., lo que probablemente desordene su código ... o puede crear funciones anónimas que se adjunten inmediatamente a estos eventos, y usted don Ya no tienes que preocuparte por ellos.
Otro uso es la programación funcional. Digamos que tienes una lista de números. Usted quiere recuperar solo aquellos números que son divisibles por tres. Es probable que haya una función llamada filter
que toma una función que devuelve un booleano y una lista, y devuelve una nueva lista que contiene solo aquellos elementos en la primera lista que, cuando se pasa a la función, devuelve True. Ejemplo:
filter(isOdd, [1, 2, 3, 5, 6, 9, 10]) --> [1, 3, 5, 9]
Sería molesto verse obligado a definir una función "isDivisibleByThree", luego pasarla a filtro, por lo que otro uso para las funciones anónimas sería crear rápidamente una función que no necesitarás en otro lugar y pasarla a filtro.
Los métodos anónimos son útiles en la programación funcional, pero también pueden ayudarlo a escribir un código más compacto en la programación estructurada. Threading, por ejemplo: http://blogs.codegear.com/abauer/2008/09/08/38868
Otros casos de uso para su "emoción" :): http://delphi.fosdal.com/2008/08/anonymous-methods-when-to-use-them.html
Por favor, eche un vistazo a los closures .
Las funciones anónimas de Delphi son cierres.
Estos se crean dentro de otras funciones y, como tal, tienen acceso al alcance de esa función. Esto es así incluso si la función anónima se asigna a un parámetro de función que se llama después de que se invoca la función original. (Crearé un ejemplo en un momento).
type
TAnonFunc = reference to procedure;
TForm2 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
F1 : TAnonFunc;
F2 : TAnonFunc;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
a : Integer;
begin
a := 1;
F1 := procedure
begin
a := a + 1;
end;
F2 := procedure
begin
Memo1.Lines.Add(IntToStr(a));
end;
end;
El método anterior asigna dos funciones anónimas a los campos F1 y F2. El primero aumenta la variable local y el segundo muestra el valor de la variable.
procedure TForm2.Button2Click(Sender: TObject);
begin
F1;
end;
procedure TForm2.Button3Click(Sender: TObject);
begin
F2;
end;
Ahora puede llamar a ambas funciones y acceder a la misma a. Llamar a F1 dos veces y F2 una vez muestra un 3. Por supuesto, este es un ejemplo simple. Pero puede expandirse a un código más útil.
En el entorno de multi-threading, las funciones anónimas se pueden utilizar en una llamada a Synchronize, que elimina la necesidad de innumerables métodos.
Puede ser este ejemplo puede ser de algún valor para usted. Aquí voy a implementar una lista de visualización con zoom para dibujar en un TCanvas sin declarar diferentes tipos de clases de visualización. También hace un uso intensivo de Genéricos. Supongamos que tenemos un TForm con un TPaintBox y un TTrackBar en él ...
type
TDisplayProc = TProc<TCanvas>;
type
TFrmExample3 = class(TForm)
pbxMain: TPaintBox;
trkZoom: TTrackBar;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure pbxMainClick(Sender: TObject);
procedure pbxMainMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
procedure pbxMainPaint(Sender: TObject);
procedure trkZoomChange(Sender: TObject);
private
FDisplayList: TList<TDisplayProc>;
FMouseX: Integer;
FMouseY: Integer;
FZoom: Extended;
procedure SetZoom(const Value: Extended);
protected
procedure CreateCircle(X, Y: Integer);
procedure CreateRectangle(X, Y: Integer);
function MakeRect(X, Y, R: Integer): TRect;
public
property Zoom: Extended read FZoom write SetZoom;
end;
implementation
{$R *.dfm}
procedure TFrmExample3.PaintBox1Paint(Sender: TObject);
var
displayProc: TDisplayProc;
begin
for displayProc in FDisplayList do
displayProc((Sender as TPaintBox).Canvas);
end;
procedure TFrmExample3.CreateCircle(X, Y: Integer);
begin
FDisplayList.Add(
procedure (Canvas: TCanvas)
begin
Canvas.Brush.Color := clYellow;
Canvas.Ellipse(MakeRect(X, Y, 20));
end
);
end;
procedure TFrmExample3.CreateRectangle(X, Y: Integer);
begin
FDisplayList.Add(
procedure (Canvas: TCanvas)
begin
Canvas.Brush.Color := clBlue;
Canvas.FillRect(MakeRect(X, Y, 20));
end
);
end;
procedure TFrmExample3.FormCreate(Sender: TObject);
begin
FDisplayList := TList<TDisplayProc>.Create;
end;
procedure TFrmExample3.FormDestroy(Sender: TObject);
begin
FreeAndNil(FDisplayList);
end;
function TFrmExample3.MakeRect(X, Y, R: Integer): TRect;
begin
Result := Rect(Round(Zoom*(X - R)), Round(Zoom*(Y - R)), Round(Zoom*(X + R)), Round(Zoom*(Y + R)));
end;
procedure TFrmExample3.pbxMainClick(Sender: TObject);
begin
case Random(2) of
0: CreateRectangle(Round(FMouseX/Zoom), Round(FMouseY/Zoom));
1: CreateCircle(Round(FMouseX/Zoom), Round(FMouseY/Zoom));
end;
pbxMain.Invalidate;
end;
procedure TFrmExample3.pbxMainMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
FMouseX := X;
FMouseY := Y;
end;
procedure TFrmExample4.SetZoom(const Value: Extended);
begin
FZoom := Value;
trkZoom.Position := Round(2*(FZoom - 1));
end;
procedure TFrmExample4.trkZoomChange(Sender: TObject);
begin
Zoom := 0.5*(Sender as TTrackBar).Position + 1;
pbxMain.Invalidate;
end;
Solo piense en el código de devolución de llamada típico donde necesita tener datos disponibles para la devolución de llamada. A menudo, estos datos son necesarios solo para la devolución de llamada, sin embargo, debe pasar por varios aros para llegar hasta allí sin tener que renunciar a prácticas no compatibles con OOP, como las variables globales. Con métodos anónimos, los datos pueden permanecer tal como están: no es necesario ampliar innecesariamente su alcance o copiarlo en algún objeto auxiliar. Simplemente escriba su código de devolución de llamada en el lugar como un método anónimo y puede acceder y manipular completamente todas las variables locales en el sitio donde se define el método anónimo (¡no cómo se llama!).
Hay otros aspectos de los métodos anónimos, más obviamente el hecho de que son, bueno, anónimos, pero este es el que realmente los hizo "hacer clic" para mí ...
Supongo (no sé Delphi) que esto implica que ahora puedes crear funciones como un tipo de objeto de datos. Esto significa que puede, por ejemplo, pasar funciones como parámetros a otras funciones. Ejemplo: una función de clasificación puede tomar una función de comparación como parámetro, por lo que es mucho más versátil.