• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

Kline777

Chamar evento de objecto sem saber o seu tipo

10 posts in this topic

Boas,

No .net se nós tivermos um objecto do tipo TObject podemos fazer qualquer coisa tipo

InstanciaObj.ChamarFunc();

O compilador nao faz a minima ideia se esta função existe ou nao, mas deixa compilar na mesma.

Existe algo semelhante no Delphi, que vi à pouco tempo mas que nao consigo recordar. Basicamente tenho uma variavel que pode ser de varios tipos diferentes, nao descendentes e quero chamar uma funçao que vou implementar nesses tipos, mas nao quero fazer os respectivos castings para evitar 'uses' desnecessarios.

Obrigado

0

Share this post


Link to post
Share on other sites

Não percebi o que precisas...

Por acaso não estás a falar do tipo Variant?

0

Share this post


Link to post
Share on other sites

Class 1 tem um evento Chamado Func();

Class 2 tem um evento Chamado Func();

num form tenho uma variavel chama obj do tipo TObject que contem um objecto q pode ser da class 1 ou 2 mas que eu nao sei, NEM QUERO SABER de qual é.

No .net posso fazer logo obj.Func(); e só na execuçao é que ele se preocupa se o obj tem de facto a func() ou nao.

Ou seja, o compilador nao dá erro, porque assume que na altura da execução em que la chegar o obj será de uma class que implemente o func()

0

Share this post


Link to post
Share on other sites

Com typecast sei que dá

TClass1(obj).Func()

Sem isso, sei que dá, que também já li isso, mas também não me lembro de como era...

0

Share this post


Link to post
Share on other sites

Pois... eu tenho a impressao que ja vi isso sem qalquer cast... mas se calhar ando a sonhar ^^

0

Share this post


Link to post
Share on other sites

No Delphi não conheço uma forma "direta" de fazer o que pretendes. O que viste podem ter sido chamadas a funções de objectos ActiveX sem usar TypeLibrary (TLB), sabendo os nomes dos métodos que se pretendem chamar.

No que pretendes fazer tens logo uma problema, que são os paramteros de chamada da função: ou são sempre os mesmos, ou então tens que saber qual a classe original do tal TObject para saberes que parametros passar.

Se tens controlo sobre os objetos de que pretendes chamar os métodos/funções, então podes partir de uma classe base que declara esse(s) métodos como virtuais (ou usas um interface, que obriga à implementação dos métodos na classe de implementação do interface).

Opção 1: Fazer as coisas como mandam as regras e evitando erros de runtime:

- Classe Base

TBaseClass = class
private
public
procedure CallMe; virtual;
end;

- Classe1:

TDerivedClass1 = class(TBaseClass)
private
public
procedure CallMe;
end;

implementation

procedure TDerivedClass1.CallMe;
begin
ShowMessage('Olá 1');
end;

- Classe 2

TDerivedClass2 = class(TBaseClass)
private
public
procedure CallMe;
end;

implementation

procedure TDerivedClass2.CallMe;
begin
ShowMessage('Olá 2');
end;

se o objeto que tens derivar de uma das duas classes, então também deriva da BaseClass e podes fazer:

if obj is TBaseClass then
TBaseClass(obj).CallMe;

Opção 2 - usando RTTI e ponteiros, correndo os riscos inerentes à sua utilização (funciona desde o Delphi 6, possivelmente desde anteriores também):

só funciona para chamar métodos published dos objetos (tipo properties), porque estamos a recorrer à rotina que o Delphi usa para "ligar" os eventos dos objetos às respetivas rotinas (ver help acerca do TObject.MethodAddress)

type
TProc = procedure of object; // declara um tipo que aponta para um procedure sem parametros (implementado por um objecto, daí o "of object")
TFunc = function(x: integer; y: string): Boolean of object; // declara um tipo que aponta para uma função com parametros (implementado por um objecto, daí o "of object")
// podem-se "juntar" os dois conceitos e declarar um tipo que aponta para um procedure com parametros ou funções sem parametros e até usar parametros com valores por defeito

procedure ExecuteMethod(obj: TObject; MethodName : String);
var
Proc: TProc;
Routine: TMethod;
begin
Routine.Data := Pointer(obj); // obj é o objeto que implementa o método a chamar, o tal TObject que tens
Routine.Code := obj.MethodAddress(MethodName); // tenta encontrar um endereço de um método com o nome indicado
if not Assigned(Routine.Code) then // se não encontrou o endereço, então o método não é publicado pelo obj (não está na secção [b]published[/b])
Exit;

Proc := TProc(Routine); // aponta a variável para o endereço do método -> atenção que tem que haver compatibilidade entre o tipo da variável e o método que se pretende executar, senão dá runtime error / AV
Proc; // chama o método

// se fosse uma função do tipo TFunc, com o mesmo nome (MethodName)
Func := TFunc(Routine);
Func(10,'abcd');
end;

Edited by apocsantos
0

Share this post


Link to post
Share on other sites

Pois... já ando a pensar em fazer pela primeira opçao que deste aí... até ja tenho os forms descendentes de outro, é o mais facil.

0

Share this post


Link to post
Share on other sites

Além de mais fácil é mais seguro e resulta em código mais limpo e flexível.

Edited by nuno.fonseca
0

Share this post


Link to post
Share on other sites

apesar q seria mt melhor ele usar intefaces.

pq ele teria a seu favor todo o poder da Tipagem e da verificação de assinatura de metodos.

digo. interfaces

0

Share this post


Link to post
Share on other sites

Com typecast sei que dá

TClass1(obj).Func()

Sem isso, sei que dá, que também já li isso, mas também não me lembro de como era...

mas com isso ai ele vai chamar o Func da classe TClass1 e não o da classe real do obj.

sem falar no problema q ele vai chamar o func() da TClass1 e passando o obj no EAX como se ele fosse realmente um TClass1.

assim até q seria mais seguro:

(obj as TClass1).Func();

pq vc teria uma verificação de tipo.

1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now