Ir para conteúdo


- - - - -

Chamar evento de objecto sem saber o seu tipo


  • Por favor inicie sessão para responder
9 respostas a este tópico

#1 Kline777

Kline777

    Try-Catch User

  • Membro
  • PipPipPipPip
  • 333 mensagens

Publicado 02 de Abril de 2013 - 16:44

Boas,

No .net se nós tivermos um objecto do tipo TObject podemos fazer qualquer coisa tipo
Código :
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

#2 nunopicado

nunopicado

    Unsigned User

  • Moderador
  • PipPipPipPipPipPip
  • 4895 mensagens

Publicado 02 de Abril de 2013 - 20:53

Não percebi o que precisas...
Por acaso não estás a falar do tipo Variant?

#3 Kline777

Kline777

    Try-Catch User

  • Membro
  • PipPipPipPip
  • 333 mensagens

Publicado 02 de Abril de 2013 - 22:48

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()

#4 nunopicado

nunopicado

    Unsigned User

  • Moderador
  • PipPipPipPipPipPip
  • 4895 mensagens

Publicado 02 de Abril de 2013 - 23:45

Com typecast sei que dá

Código (Delphi):
TClass1(obj).Func()

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

#5 Kline777

Kline777

    Try-Catch User

  • Membro
  • PipPipPipPip
  • 333 mensagens

Publicado 03 de Abril de 2013 - 09:16

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

#6 nuno.fonseca

nuno.fonseca

    null

  • Novo Membro
  • Pip
  • 9 mensagens

Publicado 09 de Abril de 2013 - 16:59

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
Código (Delphi):
TBaseClass = class
private
public
procedure CallMe; virtual;
end;

- Classe1:
Código (Delphi):
TDerivedClass1 = class(TBaseClass)
private
public
procedure CallMe;
end;

implementation

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

- Classe 2
Código (Delphi):
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:
Código (Delphi):
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)
Código (Delphi):
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 published)
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;

Editado por apocsantos, 18 de Setembro de 2013 - 19:35.


#7 Kline777

Kline777

    Try-Catch User

  • Membro
  • PipPipPipPip
  • 333 mensagens

Publicado 09 de Abril de 2013 - 17:38

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.

#8 nuno.fonseca

nuno.fonseca

    null

  • Novo Membro
  • Pip
  • 9 mensagens

Publicado 10 de Abril de 2013 - 12:36

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

Editado por nuno.fonseca, 10 de Abril de 2013 - 12:37.


#9 Gilson Nunes

Gilson Nunes

    void

  • Membro
  • PipPip
  • 46 mensagens

Publicado 06 de Setembro de 2013 - 23:13

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

#10 Gilson Nunes

Gilson Nunes

    void

  • Membro
  • PipPip
  • 46 mensagens

Publicado 07 de Setembro de 2013 - 18:20

Ver Mensagemnunopicado, em 02 de Abril de 2013 - 23:45, disse:

Com typecast sei que dá

Código (Delphi):
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:

Código :
(obj as TClass1).Func();


pq vc teria uma verificação de tipo.