2010-02-21 15 views
5

El siguiente código (construido solo para demostrar el problema) compila y funciona en Delphi 2010. En Delphi 2009, el compilador falla con "E2035 No hay suficientes parámetros reales".Casting procedimientos anónimos en Delphi 2009

program Project50; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

type 
    TMyProc = reference to procedure(param: integer); 

var 
    a: TProc; 
    b: TMyProc; 

begin 
    b := procedure (param: integer) 
    begin 
    end; 
    a := TProc(b); // <-- [DCC Error] Project50.dpr(19): E2035 Not enough actual parameters 
end. 

He encontrado solo un hack muy feo para evitar el problema (a: TProc absolute b). ¿Alguien sabe de una mejor solución para esta deficiencia del compilador?

[El campo TProc está realmente escondido dentro de un registro que puede almacenar varios códigos 'ejecutables' - TProcedure, TMethod y TProc. De fundición se utiliza para almacenar proc anónima específica en este campo]

Respuesta

1

he encontrado un hack # 2:.

program Project1; 

{$APPTYPE CONSOLE} 


uses 
    SysUtils; 

type 
    TMyProc = reference to procedure(param: integer); 

var 
    a: TProc; 
    b: TMyProc; 

begin 
    b := procedure (param: integer) 
    begin 
     Writeln('asdf'); 
    end; 
    PPointer(@a)^ := PPointer(@b)^; 
    a; 
    readln; 
end. 

estoy en duda lo que estás tratando de lograr mediante la asignación de TMyProc (con el argumento param) a TProc (sin argumento)?


Actualizado: Un truco # 3 (ref debe incrementar el contador, la idea es robado de System._IntfCopy):

procedure AnonCopy(var Dest; const Source); 
var 
    P: Pointer; 

begin 
    P:= Pointer(Dest); 
    if Pointer(Source) <> nil 
    then IInterface(Source)._AddRef; 
    Pointer(Dest):= Pointer(Source); 
    if P <> nil then 
    IInterface(P)._Release; 
end; 

var 
    a: TProc; 
    b: TMyProc; 

begin 
    b := procedure (param: integer) 
    begin 
     Writeln('asdf'); 
    end; 
    AnonCopy(a, b); 
// PPointer(@a)^ := PPointer(@b)^; 
    a; 
    readln; 
end. 
+0

Funciona en el caso de prueba, pero no en mi caso (un poco más complicado). Algo falla con el recuento de referencias de interfaz allí. Trataré de armar un caso de prueba más preciso. TProc es solo un área de almacenamiento para diferentes entidades de 'referencia al procedimiento', es por eso que lo estoy lanzando. Tal vez se podría hacer algo más agradable con los genéricos ... – gabr

+0

@gabr: He actualizado mi publicación para proponer el hack # 3 (debería incrementar el contador de interfaz) – kludg

+0

Gracias por todo su trabajo, pero acabo de encontrar una manera muy simple de resuelve este problema ... – gabr

2

El truco no es hacer

a := TProc(b); 

pero

TMyProc(a) := b; 

Eso compila y funciona en D2009. Proyecto de ejemplo adjunto a continuación.

program Project51; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

type 
    TMyProc = reference to procedure(var param: integer); 

    TStorage = record 
    FDelegate: TProc; 
    end; 

var 
    a : TMyProc; 
    b : TMyProc; 
    param: integer; 
    stg : TStorage; 

begin 
    b := procedure (var param: integer) 
    begin 
     param := 2*param; 
    end; 
// stg.FDelegate := TMyProc(b); // doesn't compile in Delphi 2009, compiles in Delphi 2010 
    TMyProc(stg.FDelegate) := b; 
    param := 21; 
    TMyProc(stg.FDelegate)(param); 
    Writeln(param); 
    Readln; 
end. 

Sin embargo, esto no funciona si se realiza una conversión a una variable local.

var 
    p: TProc; 
    a: TMyProc; 

TMyProc(p) := a; // this will not compile 

Curioso y más curioso.

1

Parece que la mejor manera sería usar genéricos para almacenar el tipo correcto de delegado en el registro. No se requieren hacks.

program Project51; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

type 
    TMyProc = reference to procedure(var param: integer); 

    TStorage<T> = record 
    FDelegate: T; 
    end; 

var 
    a : TMyProc; 
    b : TMyProc; 
    p : TProc; 
    param: integer; 
    stg : TStorage<TMyProc>; 

begin 
    b := procedure (var param: integer) 
    begin 
     param := 2*param; 
    end; 
    stg.FDelegate := b; 
    param := 21; 
    stg.FDelegate(param); 
    Writeln(param); 
    Readln; 
end. 
Cuestiones relacionadas