Подтвердить что ты не робот

Delphi: вызов функции, имя которой хранится в строке

Можно ли вызвать функцию, имя которой хранится в строке в Delphi?

4b9b3361

Ответ 1

Просьба дать более подробную информацию о том, чего вы пытаетесь достичь.

Насколько я знаю:

  • Невозможно вызвать такую ​​случайную функцию.
  • Для функций класса и объекта (MyObject.Function) это можно сделать с помощью RTTI, но это много работает.
  • Если вам просто нужно вызвать один конкретный тип функций (скажем, function (integer, integer): string), это намного проще.

Для последнего объявите тип функции, затем получите указатель на функцию и произведите его следующим образом:

type
  TMyFuncType = function(a: integer; b: integer): string of object;

  TMyClass = class
  published
    function Func1(a: integer; b: integer): string;
    function Func2(a: integer; b: integer): string;
    function Func3(a: integer; b: integer): string;
  public
    function Call(MethodName: string; a, b: integer): string;
  end;

function TMyClass.Call(MethodName: string; a, b: integer): string;
var m: TMethod;
begin
  m.Code := Self.MethodAddress(MethodName); //find method code
  m.Data := pointer(Self); //store pointer to object instance
  Result := TMyFuncType(m)(a, b);
end;

{...}

//use it like this
var MyClass: TMyClass;
begin
  MyClass := TMyClass.Create;
  MyClass.Call('Func1', 3, 5);
  MyClass.Call('Func2', 6, 4);
  MyClass.Destroy;
end.

Ответ 2

Вы не указали свою версию Delphi, но если у вас есть Delphi 2010 (+), вы можете сделать это с помощью расширенного RTTI, я не эксперт по ним, но я попробовал этот образец для вас:

  TProcClass = class
    public
      procedure SayHi;
      function GetSum(X,Y:Integer): Integer;
  end;

uses
  Rtti;

{ TProcClass }

procedure TProcClass.SayHi;
begin
  ShowMessage('Hi');
end;

function TProcClass.GetSum(X, Y: Integer): Integer;
begin
  ShowMessage(IntToStr(X + Y));
end;

procedure ExecMethod(MethodName:string; const Args: array of TValue);
var
 R : TRttiContext;
 T : TRttiType;
 M : TRttiMethod;
begin
  T := R.GetType(TProcClass);
  for M in t.GetMethods do
    if (m.Parent = t) and (m.Name = MethodName)then
      M.Invoke(TProcClass.Create,Args)
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ExecMethod('SayHi',[]);
  ExecMethod('GetSum',[10,20]);
end;

Хорошие вещи, если у вас есть процедура или функция с параметрами, она будет работать без дополнительной работы.

Ответ 3

Я удивлен, что никто не предложил таблицу рассылки . Для этого это и есть.

program RPS;

uses
  SysUtils,
  Generics.Collections;

type
  TDispatchTable = class(TDictionary<string, TProc>);

procedure Rock;
begin
end;

procedure Paper;
begin
end;

procedure Scissors;
begin
end;

var
  DispatchTable: TDispatchTable;

begin
  DispatchTable := TDispatchTable.Create;
  try
    DispatchTable.Add('Rock', Rock);
    DispatchTable.Add('Paper', Paper);
    DispatchTable.Add('Scissors', Scissors);

    DispatchTable['Rock'].Invoke; // or DispatchTable['Rock']();
  finally
    DispatchTable.Free;
  end;
end.

Реализация, которую я написал, использует generics, поэтому она будет работать только с Delphi 2009+. Для более старых версий, вероятно, было бы проще реализовать с помощью TStringList и шаблон команды

Ответ 4

В Delphi 2010 вы можете использовать JSON и SuperObject для вызова метода с параметрами.

http://code.google.com/p/superobject/source/browse/#svn/trunk

Если вам нужно, есть также XML-парсер для преобразования xml в json.

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure TestMethod(const value: string);
  end;

var
  Form1: TForm1;

implementation
uses superobject;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  SOInvoke(Self, 'TestMethod', SO('{value: "hello"}'));
end;

procedure TForm1.TestMethod(const value: string);
begin
  Caption := value;
end;

Ответ 5

Если вы спрашиваете, есть ли что-то вроде JavaScript eval() в Delphi, это невозможно (легко), поскольку Delphi компилируется в собственный код.

Если вам нужно только поддерживать некоторые строки, вы всегда можете сделать много if или case... Что-то вроде:

if myString = 'myFunction' then
    myFunction();

Ответ 6

Вы можете сделать что-то подобное, создав один или несколько классов с опубликованными свойствами, которые используют функции для реализации своих функций чтения и записи. Затем свойства могут быть обнаружены с использованием RTTI-отражения и ссылки, в результате чего вызывающие функции вызываются.

В качестве альтернативы вы можете хранить указатели функций в таблице или даже свойство Object TStringList и эффективно индексировать их по имени строки.

Прямой вызов функции по имени в Delphi невозможно.

Ответ 7

Поместите каждую функцию в действие. Затем вы можете найти действие по имени и выполнить его

function ExecuteActionByName(const S: String);
var
  I: Integer;
begin
  for I := 0 to MainForm.ComponentCount-1 do
    if (MainForm.Components[I] is TAction)
    and SameText(TAction(MainForm.Components[I]).Name,S) then
    begin
      TAction(MainForm.Components[I]).Execute;
      Break;
    end;
end;

Ответ 8

ОК, я очень очень поздно, но вы можете определенно вызвать подпрограммы по имени с этим кодом (есть некоторые ограничения)

type
    TExec = procedure of Object;
    // rest of section...

procedure TMainForm.ExecuteMethod(MethodName : String);
var
   Exec    : TExec;
   Routine : TMethod;
begin
     Routine.Data := Pointer(Form1);
     Routine.Code := Form1.MethodAddress(MethodName);
     if Not Assigned(Routine.Code) then
        Exit;

     Exec         := TExec(Routine);
     Exec;
end;

На всякий случай кому-то это нужно для Delphi 7/2010