2010-02-21 24 views
5

Đoạn mã sau (chỉ được xây dựng để chứng minh vấn đề) biên dịch và hoạt động trong Delphi 2010. Trong Delphi 2009, trình biên dịch không thành công với "E2035 Không đủ thông số thực tế".Đúc thủ tục ẩn danh trong 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. 

Tôi đã tìm thấy chỉ một lỗi rất xấu để giải quyết vấn đề (a: TProc tuyệt đối b). Có ai biết về một workaround đẹp hơn cho trình biên dịch này thiếu?

[Trường TProc thực sự được ẩn bên trong một bản ghi có thể lưu trữ nhiều mã 'thực thi' khác nhau - TProcedure, TMethod và TProc. Đúc được sử dụng để lưu trữ proc nặc danh cụ thể vào lĩnh vực này]

Trả lời

1

Tôi đã tìm thấy một 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. 

Tôi nghi ngờ những gì bạn đang cố gắng để đạt được bằng cách gán TMyProc (với lập luận param) để TProc (không có đối số)?


Cập nhật: Một hack # 3 (nên tăng ref truy cập, ý tưởng bị đánh cắp từ 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

Nó hoạt động trong trường hợp thử nghiệm, nhưng không phải trong trường hợp (hơi phức tạp hơn) của tôi. Đã xảy ra sự cố với tính năng tham chiếu giao diện ở đó. Tôi sẽ cố gắng kết hợp một trường hợp kiểm tra chính xác hơn. TProc chỉ là khu vực lưu trữ cho các đặc quyền 'tham chiếu đến thủ tục' khác nhau, đó là lý do tại sao tôi truyền nó. Có lẽ một cái gì đó đẹp hơn có thể được thực hiện với các generics ... – gabr

+0

@gabr: Tôi đã cập nhật bài đăng của mình để đề xuất hack # 3 (nên tăng giao diện truy cập ref) – kludg

+0

Cảm ơn tất cả công việc của bạn nhưng tôi đã tìm thấy một cách thực sự đơn giản giải quyết vấn đề này ... – gabr

2

Bí quyết không phải là để làm

a := TProc(b); 

nhưng

TMyProc(a) := b; 

Soạn thảo và hoạt động trong D2009. Dự án mẫu được đính kèm bên dưới.

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. 

Tuy nhiên, điều này không hiệu quả nếu truyền sang biến cục bộ.

var 
    p: TProc; 
    a: TMyProc; 

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

Tò mò và tò mò.

1

Dường như cách tốt nhất là sử dụng Generics để lưu trữ đúng loại đại biểu trong hồ sơ. Không yêu cầu 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. 
Các vấn đề liên quan