Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Llamar a una funcion almacenandola en una variable (https://www.clubdelphi.com/foros/showthread.php?t=29653)

papulo 27-01-2006 18:16:30

Llamar a una funcion almacenandola en una variable
 
El titulo no se si me ha salido explicativo, pero palabra que lo he intentado.

Veamos, lo que intento hacer es automatizar la llamada a una serie de funciones, todas empezando por la palabra 'SELEC' seguidas de un string diferente, que lo da el estado de ejecucion en un momento concreto.

Si tenemos los estados A, B y C, y las funciones 'SELECT_A', 'SELECT_B' y 'SELECT_C', lo que intento conseguir es que, siendo por ejemplo sStatus='A', la funcion que tengo que llamar seria 'SELECT_A', pero me gustaria ver si es posible hacer algo asi como:

Código Delphi [-]
sSelect:=('SELECT_');//El principio de todas las funciones
sSelect:=sSelect+sStatus; //Que contendria el string de la funcion SELECT_A
Lo que no se es como llamar a la funcion contenida en sSelect o si es posible.

¡Gurus de DELPHI yo os invoco! (Pero humildemente, y siempre para aprender de vuestros consejos)

Un saludo a tod@s.

Papulo.

Jonnathan 27-01-2006 19:20:29

Hola Papulo, puedes declarar todas las sentencias SQL en constantes y a la hora de llamarlas usas una función donde pases un parámetro para saber cual "Select" invocar. Mas o menos así:

Código Delphi [-]
const
SelectA = 'Select * From TablaA';
SelectB = 'Select * From TablaB';
SelectC = 'Select * From TablaC';

function BuscarSelect(MiSelect: Char): String;

implementation

function BuscarSelect(Status: Char): String;
begin
     case Status of
     A: BuscarSelect := SelectA;
     B: BuscarSelect := SelectB;
     C: BuscarSelect := SelectC;
     end;
end;
...
//LA USARIAS ASI:
BuscarSelect('A');

Si lo que deseas es usar un "Select" para la misma tabla que solo cambie el filtro, hace puedes hacer esto:

Código Delphi [-]
const
sSelect = 'Select * From MiTabla where Status=%s';
...
//PARA USAR EL SELECT O ASIGNARLO A ALGUN QUERY HACES ESTO
MiQuery.SQL.Text := Format(sSelect, [Status]);
La función Format() reemplazará el "%s" por el caracter de Status que quieras usar. Espero haberte ayudado, saludos.

roman 27-01-2006 19:21:05

Pues no, realmente esto no se puede. ¿Por qué? Porque Delphi es un lenguaje compilado y no interpretado. ¿Qué quiere decir esto? Pues quien sabe pero el caso es que una vez compilado, en el ejecutable ya no quedan referencias a los nombres de funciones, variables, etc. que hayas usado en el código fuente- sólo instrucciones en ensamblador.

Siempre hay alternativas pero dependen mucho del contexto general. Por ejemplo, suponiendo que SelectA, SelectB y SelectC son parte de un X proceso podrías tener algo como

Código Delphi [-]
type
  TProcesoX = class
  public
    function Select; virtual; abstract;
  end;

  TProcesoA = class(TProcesoX)
  public
    function Select; override;
  end;

  TProcesoB = class(TProcesoX)
  public
    function Select; override;
  end;

  TProcesoC = class(TProcesoX)
  public
    function Select; override;
  end;

Según el proceso específico que estés haciendo, instanciarás una u otra clase en una variable de la clase base TProcesoX, de manera que al llamar a Proceso.Select, el polimorfismo se encargará de escoger el correcto.

Pero esto requiere claro, que hayas estructurado tu aplicación en clases.

De no ser así o no ser factible, puedes optar por dos cosas (entre otras que se le ocurran a alguien más).

La primera es: si sólo hay un punto del programa donde debes decidir cuál función llamar, pues olvídate de complicaciones y haz el case:

Código Delphi [-]
case Status of
  0: SelectA();
  1: SelectB();
  2: SelectC();
end;

Si es algo que llamas desde distintas partes de la aplicación, podrías crearte una clase "selectora":

Código Delphi [-]
type
  TSelector = class
  private
    class function SelectA: Integer;
    class function SelectB: Integer;
    class function SelectC: Integer;
  public
    class function Select(Status: Integer): Integer;
  end;

implementation

function TSelector.Select(Estatus: Integer): Integer;
begin
  case Status of
    0: Result := Self.SelectA();
    1: Result := Self.SelectB();
    2: Result := Self.SelectC();
  end;
end;

La clase sólo tiene métodos estáticos (directiva class) de manera que no hay que crear ninguna instancia, simplemente la usas así:

Código Delphi [-]
TSelector.Select(Status);

Los métodos TSelector.SelectA, TSelector.SelectB y TSelector.SelectC también son estáticos y reemplazarían a los que tenías antes.

O bien los dejas fuera de la clase y dejas a TSelector únicamente con el método Select:

Código Delphi [-]
function TSelector.Select(Estatus: Integer): Integer;
begin
  case Status of
    0: Result := SelectA();
    1: Result := SelectB();
    2: Result := SelectC();
  end;
end;

Pero la primera opción te da un cierto orden al englobar en un sólo ente las tres funciones relacionadas.

// Saludos

roman 27-01-2006 19:23:45

¿Estamos hablando de SQL? :confused:

De ser así, quédate con la opción de Jonnathan.

// Saludos

OSKR 27-01-2006 20:41:56

No siendo SQL y reafirmando el mismo método de Román yo recomendaría el uso de punteros a funciones, esto aligeraría el código, dependiendo del problema puede q no sea necesario crear otras clases, casi imprescindible el uso del case (en mi caso Switch), e incluso se podría variar los parametros y reducir desiciones por descarte y/o usando funciones polimorfas, lo digo porq ya me he topado con problemas de este tipo

Jonnathan 27-01-2006 22:55:42

Tienes razon roman jejeje :p, no se que estaba fumando que de repente vi todo como que era SQL, debe ser que he visto muchas consultas hoy en el trabajo, ahora que vuelvo a leer entiendo lo de automatizar la función. Y tambien recuerdo hace mucho vi por ahi una manera de llamar funciones pasandolas como una cadena de texto a una función del compilador que las ejecutaba ¿o tal vez era Visual Basic? :rolleyes:. Bueno, el caso es que si quieres armar una sentencia con varias cadenas de texto y despues intentar ejecutarla te recomendaria algun componente interprete de scripts como FastScript.

Nota Mental: No responder preguntas del foro en estados de presión laboral. :rolleyes:

Lepe 28-01-2006 09:38:08

Yo me quedaría con el uso de punteros, como dice OSKR
Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  Tseleccion = function (a,b:Integer):Integer;

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

var
  Form1: TForm1;

implementation

{$R *.dfm}

function An(a,b:integer):integer ;
begin
  Result := a;
end;

function the(a,b:integer):integer ;
begin
  Result := b;
end;


procedure TForm1.Button1Click(Sender: TObject);
  var sel:Tseleccion;
begin
   sel := the;
// aqui podemos elegir tanto la funcion "the" como la funcion "An" ya que 
// ambas tienen el mismo tipo de declaración.

// incluso podemos comparar para saber que funcion tienen:
if @sel = @the then
   ShowMessage('estamos usando la funcion the ');  

// ahora la ejecutamos:
   ShowMessage(IntToStr(sel(3,5)));
end;

end.

saludos

papulo 30-01-2006 09:23:06

Lo primero es daros las gracias a todos los que habeis respondido, no me he podido conectar desde casa, no me cargaba la pagina bien.

Lo segundo, voy a mirarme las respuestas y a ver que hago.

Un saludo y feliz Lunes.

Papulo.

piccolo2101 30-01-2006 09:44:49

Bueno,
intentando, quizás, acercarme más un poco a la solución que buscas de sSelect+sStatus, voy a explicarte un método que se me ha ocurrido:
Evidentemente un puntero a una función no es más que una dirección de memoria así que sSelect podría ser una dirección de memoria que inicialmente señalase a la función Select_A. Tambíen puedes haces que al iniciar tu aplicación se calculen las diferencias entre Select_A y el resto para saber que desplazamiento debes aplicar respecto a la dirección de memoria de Select_A y esos serán los valores de sStatus. Por ejemplo
Usaré valores enteros para explicarme mejor.
Select_A ----- dirección 100
Select_B ----- dirección 150
Select_C ----- dirección 75

sSelect = 100;
posibles valores de sStatus = 0 (si es Select_A), 50 (si es Select_B), -25 (si es Select_C).

Con esto, es posibles hacer en un momento dado una llamada a la función que quieras con sSelect+sStatus.

Respecto a lo de lenguaje compilado e interpretado discreparé un poquito, siempre desde mi ignorancia, porque lenguajes relativamente interpretados como java o perl requieren de una fase de precompilación para generar el código interpretado y en éste también se han traducido los nombres de funciones y demás por direcciones. Sé que perl tiene una función que permite hacer lo que quieres llamada eval si mal no recuerdo y es posible que realice un cálculo relativo de la posición de memoria de dicha función.

PD: Te recomiendo que calcules los desplazamientos de las funciones respecto a una base (en este caso Select_A) porque una vez los tengas ya puedes cambiar tu código y hacerlo constante ya que la distancia debería ser siempre la misma salvo que modifiques código.

Un saludo y gracias.

OSKR 30-01-2006 18:24:32

Jonnathan:
Cita:

Y tambien recuerdo hace mucho vi por ahi una manera de llamar funciones pasandolas como una cadena de texto a una función del compilador que las ejecutaba ¿o tal vez era Visual Basic? :rolleyes:.
En mi caso ese fue DBase....Clipper, y se llamaban "Macros", no solo funciones sino q se podían armar sentencias y además era un ejecutable (bueno..el último, DBase era otra vaina!)
piccolo2101:
Cita:

Evidentemente un puntero a una función no es más que una dirección de memoria así que sSelect podría ser una dirección de memoria que inicialmente señalase a la función Select_A. Tambíen puedes haces que al iniciar tu aplicación se calculen las diferencias entre Select_A y el resto para saber que desplazamiento debes aplicar respecto a la dirección de memoria de Select_A y esos serán los valores de sStatus. Por ejemplo
Usaré valores enteros para explicarme mejor.
Select_A ----- dirección 100
Select_B ----- dirección 150
Select_C ----- dirección 75
Jjjjjjjjjmmmmmmmmm, llevo algunos añitos jugando con punteros en todo cuanto pueda.......pero de ahí a jugar con los desplazamientos y diferencias entre ellos es algo tenebroso, yo particularmente no los emplearía así y menos sin saber si el compilador usa Overlay

roman 30-01-2006 19:10:01

La verdad creo que se están complicando demasiado. Se tienen tres funciones, Select_A, Select_B y Select_C y se les quiere llamar de manera genérica sabiendo como dato el estado "A", "B" o "C".

Si no se quiere introducir clases entonces basta con esta función:

Código Delphi [-]
function Select(Estado: Char): Integer;
begin
  case Estado of
    'A': Result := Select_A();
    'B': Result := Select_B();
    'C': Result := Select_C();
  end;
end;

simplemente llamándola con

Código Delphi [-]
Select(Estado);

// Saludos

OSKR 30-01-2006 23:30:12

Eeeeeeehhhhhhhh....puess.........essssteeee....sip, es verdad, pero creo q a veces es necesario ahondar para casos extremos :). Por lo menos a mi me ha servido ;).

roman 31-01-2006 06:53:47

Cita:

Empezado por OSKR
a veces es necesario ahondar para casos extremos

Sí, pero a veces es extremo ahondar en casos innecesarios ;)

Creo que termina uno confundiendo a la gente. De hecho me alegra que hayas mencionado el lado tenebroso.

// Saludos

piccolo2101 31-01-2006 09:31:35

Hola,
estoy totalmente de acuerdo con la sencillez de la solución planteada por roman y, por supuesto, estoy más de acuerdocon las palabras de OSKR pero mi intención sólo era dar una posible solución al problema según se había planteado pero que yo nunca usaría. Básicamente era una respuesta al estilo : "Por poder, se puede..." que una solución viable.

Por cierto, aquí dejo otra más factible:
Se puede crear un array de punteros a funciones que inicialmente guarde las funciones Select_A, Select_B y Select_C en las posiciones 0,1,2 del array.
Sabiendo que sStatus es de tipo enumerado (p.ejemplo) y hacemos que el enumerado coincida con las posiciones dentro del array de las funciones se podría llamar a la función sin hacer distinción con case sólo con sSelect[sStatus].


Un saludo.

cuburu 01-02-2006 03:54:05

Hola,
Ya metiendome en este tema yo diría lo siguiente:

Utilización de punteros.... mmmmm creo que no debido a que no es muy factible estar jugando con desplazamientos de memoria y direccionamientos esperando que la maquina nunca se atrofie. Java es un claro ejemplo de ello, eliminó el manejo de punteros debido a estos pequeños detalles jejeje.

Sería mejor trabajar con polimorfismo y creo que es más recomendable debido a que es una forma de programar ordenada y que también, o no se que opinen ustedes, ..... Delphi esta creado para trabajar de esa manera aunque a algunos de nosotros se nos olvida eso de vez en cuando jajajaja.

Buen debate chavos, más de estos temas... :D

OSKR 02-02-2006 18:19:25

Roman
Cita:

Creo que termina uno confundiendo a la gente. De hecho me alegra que hayas mencionado el lado tenebroso.
Claro, la gente ha de saber hasta q punto puede trabajar....y...bueno.......lo de tenebroso es relativo....generalmente C es así...pascal también ;).
cuburu
Cita:

Utilización de punteros.... mmmmm creo que no debido a que no es muy factible estar jugando con desplazamientos de memoria y direccionamientos esperando que la maquina nunca se atrofie. Java es un claro ejemplo de ello, eliminó el manejo de punteros debido a estos pequeños detalles jejeje.
El uso de punteros es para qienes realmente lo manejen y sean responsables de lo q hacen, en mi caso, evitan una multitud de código como es el caso de java, es más! java usa casi para todo punteros indirectamente como Builder con sus componentes solo q de manera discreta ....y lenta...
Por ejemplo:
Código:

Objeto *Obj=new Objeto[500];
en comparación con
Código:

Objeto [] Obj= new Objeto[500];
for(int i=0;i<500;i++)
 Obj[i]=new Objeto();

la diferencia en cientos de instrucciones es notable


La franja horaria es GMT +2. Ahora son las 18:22:34.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi