Кастинг анонимных процедур в Delphi 2009

Следующий код (создал только для демонстрации проблемы), компиляции и работы в Delphi 2010. В Delphi 2009 компилятор приводит к сбою с "E2035 Недостаточно фактических параметров".

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.

Я нашел, что только один очень ужасный взлом работает вокруг проблемы (a: TProc, абсолютный b). Кто-либо знает о более хорошем обходном решении для этого дефицита компилятора?

[Поле TProc на самом деле скрыто в записи, которая может сохранить различный 'исполняемый' код - TProcedure, TMethod и TProc. Кастинг используется для хранения определенного анонимного proc в это поле.]

5
задан gabr 21 February 2010 в 20:00
поделиться

3 ответа

Я нашел хак #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.

Я сомневаюсь, чего вы пытаетесь достичь, присваивая TMyProc (с аргументом param) TProc (без аргумента)?


Обновлено: Хак #3 (должен инкрементировать счетчик ссылок, идея украдена из 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.
1
ответ дан 15 December 2019 в 00:59
поделиться

Я думаю, вы имеете в виду:

D code = new D(x.ToString);

Обратите внимание на отсутствие скобок. В скобках на, это был метод вызов , то есть вы пытались выполнить x.ToString () в этой строке кода. Без скобок это группа методов - выражение, которое подсказывает компилятору взглянуть на доступные методы с таким именем (в данном контексте), именно с целью создания делегатов.

Какую книгу вы используете? Если он действительно имеет скобки в примерах, вы можете отправить письмо автору (или, по крайней мере, проверить страницу с ошибками книги). Если это C # в глубине, я пойду и буду плакать в углу...

-121--2434779-

Должно быть:

D code = new D(x.ToString);
-121--2434783-

Хитрость состоит не в том, чтобы делать

a := TProc(b);

, а в том, чтобы

TMyProc(a) := b;

компилировать и работать в D2009. Образец проекта прилагается ниже.

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.

Однако это не работает, если выполняется приведение к локальной переменной.

var
  p: TProc;
  a: TMyProc;

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

Курьер и курьер.

2
ответ дан 15 December 2019 в 00:59
поделиться

Похоже, что лучший способ - использовать дженерики для хранения правильного типа делегата в запись. Никаких взломов не требуется.

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.
1
ответ дан 15 December 2019 в 00:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: