Следующий код (создал только для демонстрации проблемы), компиляции и работы в 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 в это поле.]
Я нашел хак #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.
Я думаю, вы имеете в виду:
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
Курьер и курьер.
Похоже, что лучший способ - использовать дженерики для хранения правильного типа делегата в запись. Никаких взломов не требуется.
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.