Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Prüfen, ob Klasse ein Interface implementiert?


sunnyandy - So 11.11.07 21:15
Titel: Prüfen, ob Klasse ein Interface implementiert?
Hallo,

ich habe mittels zweier Interfaces das Observer-Pattern implementiert. Bei einer Änderung führt das Observable bei dem Beobachter die Methode Aktualisieren(Sender: TObject) aus. Dort wird immer eine Referenz auf die eigene Klasse mit übergeben.

Nun möchte ich im Observer überprüfen, von welcher Klasse die Aktualisieren Methode aufgerufen wird (Es kann ja mehrere Observable geben). Ich möchte wissen, ob die beobachtbare Klasse (Observable) ein FilterFrame ist (Meine FilterFrames implementieren nämlich IFilterFrame). "IS" kann man so wie es aussieht aber nicht auf Interfaces anwenden.
Wie kann ich hier prüfen, ob die übergebene Klasse IFilterFrame implementiert?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
{*
  Observer-Methode.
}

procedure TFrameKundenliste.Aktualisieren(Sender: TObject);
begin
  if Sender is IFilterFrame then
  ...

end;


Sonst geht es doch mit Klassen wunderbar:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TFrameKundenliste.Aktualisieren(Sender: TObject);
begin
  if Sender is TMeinObject then
  begin
    (Sender as TMeinObject).Methode1;
    ...
  end;

end;


Danke im Voraus!
Andy


dummzeuch - So 11.11.07 22:55
Titel: Re: Prüfen, ob Klasse ein Interface implementiert?
user profile iconsunnyandy hat folgendes geschrieben:
Nun möchte ich im Observer überprüfen, von welcher Klasse die Aktualisieren Methode aufgerufen wird (Es kann ja mehrere Observable geben). Ich möchte wissen, ob die beobachtbare Klasse (Observable) ein FilterFrame ist (Meine FilterFrames implementieren nämlich IFilterFrame). "IS" kann man so wie es aussieht aber nicht auf Interfaces anwenden.
Wie kann ich hier prüfen, ob die übergebene Klasse IFilterFrame implementiert?


Der IS Operator funktioniert bei Interfaces nur, wenn das Interface eine GUID hat (Ctrl-Alt-G oder war's Shift-Ctrl-G im Editor zum Erzeugen).


Delphi-Quelltext
1:
2:
3:
type
  IFilterFrame = interface [guid hier]
    ...


twm


sunnyandy - So 11.11.07 23:13

Hallo,

danke für deine Antwort!
Ich habe es ausprobiert, es funktioniert aber leider nicht.
Fehler: Operator ist auf diesen Operandentyp nicht anwendbar


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
interface
  uses
    Observable;

  type IFilterFrame = interface(IObservable)
  ['{805F0FA9-5665-4020-BA24-0FADBBDE28EB}']
    procedure AktualisiereAnzahl(AnzahlSelektion: integer; AnzahlAlle: integer);
  end;
...


Das müsste so richtig sein oder?


sunnyandy - Mo 12.11.07 01:09

Ich denke ich kann das nun folgendermaßen abfragen:


Delphi-Quelltext
1:
2:
3:
4:
5:
if Supports(Sender, IFilterFrame) then
  begin
    FilterFrame := (Sender as IFilterFrame); // <- Funktioniert nicht!
    FilterFrame.DoSomething;
  end;


Wie bekomme ich denn den TypeCast von TObject zum Interface hin? Es will einfach nicht funktionieren.


dummzeuch - Mo 12.11.07 19:22

user profile iconsunnyandy hat folgendes geschrieben:
Ich denke ich kann das nun folgendermaßen abfragen:


Delphi-Quelltext
1:
2:
3:
4:
5:
if Supports(Sender, IFilterFrame) then
  begin
    FilterFrame := (Sender as IFilterFrame); // <- Funktioniert nicht!
    FilterFrame.DoSomething;
  end;


Wie bekomme ich denn den TypeCast von TObject zum Interface hin? Es will einfach nicht funktionieren.


Ohne es jetzt getestet zu haben:

Delphi-Quelltext
1:
2:
if S_OK = (Sender as TInterfaceObject).QueryInterface(IFilterFrame, FilterFrame) then
  FilterFrame.DoSomething;


twm


MrSaint - Mo 12.11.07 20:23

user profile iconsunnyandy hat folgendes geschrieben:
Ich denke ich kann das nun folgendermaßen abfragen:


Delphi-Quelltext
1:
2:
3:
4:
5:
if Supports(Sender, IFilterFrame) then
  begin
    if (Sender is IFilterFrame) then 
      FilterFrame.DoSomething;
  end;


Wie bekomme ich denn den TypeCast von TObject zum Interface hin? Es will einfach nicht funktionieren.


dummzeuch - Mo 12.11.07 20:30

user profile iconMrSaint hat folgendes geschrieben:
user profile iconsunnyandy hat folgendes geschrieben:
Ich denke ich kann das nun folgendermaßen abfragen:


Delphi-Quelltext
1:
2:
3:
4:
5:
if Supports(Sender, IFilterFrame) then
  begin
    if (Sender is IFilterFrame) then 
      FilterFrame.DoSomething;
  end;


Wie bekomme ich denn den TypeCast von TObject zum Interface hin? Es will einfach nicht funktionieren.


Aeh? Und die Zuweisung von FilterFrame erfolgt durch Magie??

twm


MrSaint - Mo 12.11.07 20:32

puh, sorry.... man sollte mal genau lesen ;) Einfach meinen Quark hier vergessen :D


Allesquarks - Mo 12.11.07 22:34

Wenn man mit Interface Variablen arbeitet verbergen sich dahinter auch immer nur normale Klassen allerdings darf man sie solange man sie als interface anspricht nur mit den Interface Methoden arbeiten alla:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
type myinterface = interface(IUnknown)
 function getref:class of TObject;
end;

type myclass1 = class(TObject,Myinterface)

end;

//und die anderen myclass2 identisch/analog

implementation

function TMyclass1.getref:class of TObject;
begin
  result:=self.classtype;
end;


Wie man hier sieht ist das etwas trickey, da interfaces nur Methoden definieren und keine Variablen selbst haben deshalb die Klassenreferenz selbst mitschleppen. Die könntest du jetzt direkt vergleichen so alla:

Delphi-Quelltext
1:
2:
3:
4:
5:
   klassentyp:=myinterfacevar.getref;
   case klassentp of 
     myclass1:...;
     myclass2:...;
   end;


Was aber ebenfalls geht ist, da sich hinter jedem Interface ein Object verbirgt es einfach als Object ansprechen das heißt auf TObject casten und dann classtype benutzen alla:


Delphi-Quelltext
1:
2:
3:
4:
  if TObject(myinterfacevar) is myclass1 
  then begin
     //...
  end;


//Edit:

Wenn du sowieso schon weißt, dass deine Klasse dieses Interface unterstützt dann sollte es ja auch reichen zu überprüfen welche Klasse es ist mit dem is-Operator. So heißt es auch in einer Zeile bei dir. Falls es da partout keinen Befehl gibt kann man da auch einen Workaround machen, da diese Information meistens bei Compilierzeit feststehen sollte kannst du einfach eine Liste mit Klassen machen welche dies und das unterstützen und mit der vergleichen.

Was auch möglich wäre alle Objekte ein Interface Iinterfacechecklist implementieren zu lassen die immer ja nein zurückgeben wenn sie es unterstützen.


sunnyandy - Di 13.11.07 00:26

Hallo,

vielen Dank für eure Antworten!
man kann mithilfe "Supports" gleich einen Verweis auf das Objekt herstellen...
Diese Lösung hier funktioniert wunderbar:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure TFrameKundenliste.Aktualisieren(Sender: TObject);
var
  FilterFrame: IFilterFrame;
begin
  if Supports(Sender, IFilterFrame, FilterFrame) then
    FilterFrame.DoSomething; 
  ...


Es klappt :-)