2008-11-01 22 views
28

Delphi 2009, entre algunas cosas interesantes, también tiene 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?¿Alguien me puede explicar métodos anónimos?

Respuesta

11

Sólo piensa en código de devolución de llamada típica en la que es necesario tener datos disponibles para la devolución de llamada. A menudo, estos datos son necesarios para la devolución de llamada , solo, sin embargo, debe pasar por varios aros para obtenerlo sin tener que renunciar a prácticas no compatibles con OOP como 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, la mayoría, obviamente, el hecho de que son, así: en el anonimato, pero esta es la que realmente les hizo ir "clic" para mí ...

+1

Este es el único comentario que me hizo decir 'AHA'. Todavía no estoy 100% emocionado, pero al menos puedo ver un uso en el mundo real ahora. – Steve

1

Supongo (no sé Delphi) esto implica que ahora puede 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.

+1

parcialmente. Delphi ya tiene indicadores de función. Pero ahora pueden crearse anónimamente. Ver mi comentario –

15

Por favor, eche un vistazo a closures.

Las funciones anónimas de Delphi son cierres.

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 Sincronizar, lo que elimina la necesidad de innumerables métodos.

+1

bien, ¡pero todavía no estoy emocionado! Genéricos que me entusiasman porque puedo ver cientos de lugares donde puedo usarlos. Los métodos anónimos aún me dejan frío. – Steve

+1

No tiene que estar emocionado, encontrará un uso para ellos ;-). –

+0

Tal vez emocionado no es la palabra correcta, pero lo que quiero decir es que no puedo pensar en un ejemplo del mundo real (todavía) donde diría "Sí, eso es exactamente lo que son los métodos de Anaoymous" – Steve

11

Que sea 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 una 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; 
5

La gente ya ha proporcionado el código, así que voy a enumerar algunos lugares donde pueden ser útiles.

Digamos que tiene un código de 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] 

que sería molesto para ser obligada a definir una función "isDivisibleByThree", luego pasarlo a filtrar, por lo que otro uso de funciones anónimas aquí sería simplemente para crear rápidamente una función que no lo hará necesita otro lugar y pásalo para filtrar.

Cuestiones relacionadas