Implementiert eine Komponente ein Interface?
-
- Beiträge: 369
- Registriert: Do 8. Jun 2017, 18:21
- OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10, FPC 3.2.0
- CPU-Target: 64Bit
- Wohnort: Wien
Implementiert eine Komponente ein Interface?
Ich habe einige eigene Komponenten entwickelt (von Standard LCL Komponenten abgeleitet), die alle das Interface IfdData implementieren sollen. Eine der Interface Methoden heisst z.B. Clear.
Jetzt würde ich gerne zur Laufzeit alle Komponenten einer Form durchgehen und bei den Komponenten, die mein Interface unterstützen, die Methode Clear aufrufen. Komponenten, die das Interface nicht unterstützen, sollen dabei einfach übergangen werden (die haben ja keine Clear Methode). Ich habe jetzt eine Weile herumprobiert, aber ich komme nicht drauf, wie man das syntaktisch richtig umsetzt.
Jetzt würde ich gerne zur Laufzeit alle Komponenten einer Form durchgehen und bei den Komponenten, die mein Interface unterstützen, die Methode Clear aufrufen. Komponenten, die das Interface nicht unterstützen, sollen dabei einfach übergangen werden (die haben ja keine Clear Methode). Ich habe jetzt eine Weile herumprobiert, aber ich komme nicht drauf, wie man das syntaktisch richtig umsetzt.
-
- Beiträge: 2013
- Registriert: Do 16. Okt 2008, 10:22
- OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
- CPU-Target: x86,x64,ARM
Re: Implementiert eine Komponente ein Interface?
TObject.GetInterface() dient zu diesem Zweck:
https://www.freepascal.org/docs-html/cu ... rface.html
Das Interface muss eine GUID (bei COM-Interface) oder einen ID-string (bei Corba-Interface) haben.
https://www.freepascal.org/docs-html/cu ... rface.html
Das Interface muss eine GUID (bei COM-Interface) oder einen ID-string (bei Corba-Interface) haben.
-
- Beiträge: 369
- Registriert: Do 8. Jun 2017, 18:21
- OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10, FPC 3.2.0
- CPU-Target: 64Bit
- Wohnort: Wien
Re: Implementiert eine Komponente ein Interface?
Das schaut so aus, als wäre es, was ich brauche - aber wie ich es verwenden muss, ist mir auch nach dem Lesen der Dokumentation noch immer nicht klar.
1. Wie komme ich zum Parameter GUID?
Ich deklariere das Interface beispielsweise als
IfdData = Interface ['{0AB00115-0734-0184-C000-0C5600052148}'']
(Nebenbei: Gibt es eigentlich irgend welche Richtlinien, wie man den GUID String aufbauen soll, oder macht man das völlig willkürlich? In der Delphi-IDE gibt es glaube ich sogar ein Tastaturkürzel, das einen GUID String generiert)
Woher bekomme ich die GUID Variable - oder muss ich den GUID-String zu Fuß in den GUID Typ konvertieren?
Und was übergebe ich im Parameter obj? Die Komponente selbst steht doch schon vor dem Punkt: abc.GetInterface( guid, ????); Was muss denn da hin? obj ist ein OUT Parameter.
1. Wie komme ich zum Parameter GUID?
Ich deklariere das Interface beispielsweise als
IfdData = Interface ['{0AB00115-0734-0184-C000-0C5600052148}'']
(Nebenbei: Gibt es eigentlich irgend welche Richtlinien, wie man den GUID String aufbauen soll, oder macht man das völlig willkürlich? In der Delphi-IDE gibt es glaube ich sogar ein Tastaturkürzel, das einen GUID String generiert)
Woher bekomme ich die GUID Variable - oder muss ich den GUID-String zu Fuß in den GUID Typ konvertieren?
Und was übergebe ich im Parameter obj? Die Komponente selbst steht doch schon vor dem Punkt: abc.GetInterface( guid, ????); Was muss denn da hin? obj ist ein OUT Parameter.
-
- Beiträge: 2013
- Registriert: Do 16. Okt 2008, 10:22
- OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
- CPU-Target: x86,x64,ARM
Re: Implementiert eine Komponente ein Interface?
braunbär hat geschrieben:Das schaut so aus, als wäre es, was ich brauche - aber wie ich es verwenden muss, ist mir auch nach dem Lesen der Dokumentation noch immer nicht klar.
1. Wie komme ich zum Parameter GUID?
Ich deklariere das Interface beispielsweise als
IfdData = Interface ['{0AB00115-0734-0184-C000-0C5600052148}'']
Dann kannst du
Code: Alles auswählen
if <objektinstanz>.getinterface('{0AB00115-0734-0184-C000-0C5600052148}',<interfacevariable>) then begin
tue etwas mit dem interface
end;
verwenden.
(Nebenbei: Gibt es eigentlich irgend welche Richtlinien, wie man den GUID String aufbauen soll, oder macht man das völlig willkürlich?
Diese ID soll "Globally Unique" also welt- oder universumweit einmalig sein.
In der Delphi-IDE gibt es glaube ich sogar ein Tastaturkürzel, das einen GUID String generiert)
Das gibt es in Lazarus sicher auch. In MSEide wäre es RightClick-'Insert GUID'.
Woher bekomme ich die GUID Variable - oder muss ich den GUID-String zu Fuß in den GUID Typ konvertieren?
Siehe oben. Eine andere Option ist
Code: Alles auswählen
if <objektinstanz>.getinterface(stringtoguid('{0AB00115-0734-0184-C000-0C5600052148}'),<interfacevariable>) then begin
tue etwas mit dem interface
end;
EDIT: oder besser
Code: Alles auswählen
if <objektinstanz>.getinterface(<interfacetyp>,<interfacevariable>) then begin
tue etwas mit dem interface
end;
welches direkt mit TGUID arbeitet.
Und was übergebe ich im Parameter obj? Die Komponente selbst steht doch schon vor dem Punkt: abc.GetInterface( guid, ????); Was muss denn da hin? obj ist ein OUT Parameter.
"obj" ist die Interface Variable.
PS: Falls du COM-Interface verwendest (die Standardeinstellung), solltest du dir überlegen, ob nicht CORBA-Interface besser geeignet wären.
Zuletzt geändert von mse am Mi 3. Okt 2018, 08:35, insgesamt 2-mal geändert.
-
- Beiträge: 369
- Registriert: Do 8. Jun 2017, 18:21
- OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10, FPC 3.2.0
- CPU-Target: 64Bit
- Wohnort: Wien
Re: Implementiert eine Komponente ein Interface?
Danke für die Antwort, mit den Infos sollte ich weiterkommen.
Ich benötige die Interfaces in dem Framework hier eigentlich nur, um auf einer abstrakten Ebene manche Aufgaben für die Komponenten einer Form automatisch erledigen zu können, die die entsprechende Funkionalität bereitstellen. Wenn es auf der Form noch andere Komponenten gibt, dann muss sich der Programmierer der Form (zur Zeit meistens auch ich selbst) in einer Callback Routine um diese Komponenten individuell kümmern.
Keine Ahnung, ob Corba da irgend einen Vorteil bieten würde. Es geht hier explizit nicht um Schnittstellen nach außen zu anderen Programmen.
Was ich gerne wissen würde, ist noch, ob die Prüfung auf Vorhandensein des Interfaces zeitaufwändig ist - ich vermute aber eher (und hoffe), dass das nicht der Fall ist.
Edit: Nochmals danke, das hat jetzt auf Anhieb funktioniert.
Ich benötige die Interfaces in dem Framework hier eigentlich nur, um auf einer abstrakten Ebene manche Aufgaben für die Komponenten einer Form automatisch erledigen zu können, die die entsprechende Funkionalität bereitstellen. Wenn es auf der Form noch andere Komponenten gibt, dann muss sich der Programmierer der Form (zur Zeit meistens auch ich selbst) in einer Callback Routine um diese Komponenten individuell kümmern.
Keine Ahnung, ob Corba da irgend einen Vorteil bieten würde. Es geht hier explizit nicht um Schnittstellen nach außen zu anderen Programmen.
Was ich gerne wissen würde, ist noch, ob die Prüfung auf Vorhandensein des Interfaces zeitaufwändig ist - ich vermute aber eher (und hoffe), dass das nicht der Fall ist.
Edit: Nochmals danke, das hat jetzt auf Anhieb funktioniert.
Zuletzt geändert von braunbär am Di 2. Okt 2018, 21:29, insgesamt 1-mal geändert.
-
- Beiträge: 576
- Registriert: Sa 22. Okt 2016, 23:12
- OS, Lazarus, FPC: W10, L 2.2.6
- CPU-Target: 32+64bit
- Wohnort: Dresden
Re: Implementiert eine Komponente ein Interface?
GUID Tastenkürzel: Shift+Strg+G siehe Menü -> Quelltext -> Einfügen allgemein -> GUID einfügen
selbst eine erzeugen:
selbst eine erzeugen:
Code: Alles auswählen
var
T : TGUID;
begin
CreateGUID(T);
ShowMessage(GUIDToString(T));
end;
LG Maik
Windows 10,
- Lazarus 2.2.6 (stable) + fpc 3.2.2 (stable)
- Lazarus 2.2.7 (fixes) + fpc 3.3.1 (main/trunk)
Windows 10,
- Lazarus 2.2.6 (stable) + fpc 3.2.2 (stable)
- Lazarus 2.2.7 (fixes) + fpc 3.3.1 (main/trunk)
-
- Beiträge: 369
- Registriert: Do 8. Jun 2017, 18:21
- OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10, FPC 3.2.0
- CPU-Target: 64Bit
- Wohnort: Wien
Re: Implementiert eine Komponente ein Interface?
Gut zu wissen.
Habs gerade ausprobiert. So schön wie meine GUID sind die aber nicht
Habs gerade ausprobiert. So schön wie meine GUID sind die aber nicht
-
- Beiträge: 2013
- Registriert: Do 16. Okt 2008, 10:22
- OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
- CPU-Target: x86,x64,ARM
Re: Implementiert eine Komponente ein Interface?
braunbär hat geschrieben:Danke für die Antwort, mit den Infos sollte ich weiterkommen.
Ich benötige die Interfaces in dem Framework hier eigentlich nur, um auf einer abstrakten Ebene manche Aufgaben für die Komponenten einer Form automatisch erledigen zu können, die die entsprechende Funkionalität bereitstellen. Wenn es auf der Form noch andere Komponenten gibt, dann muss sich der Programmierer der Form (zur Zeit meistens auch ich selbst) in einer Callback Routine um diese Komponenten individuell kümmern.
Dann würde ich auf jeden Fall CORBA einsetzen.
Keine Ahnung, ob Corba da irgend einen Vorteil bieten würde. Es geht hier explizit nicht um Schnittstellen nach außen zu anderen Programmen.
Die üblichen COM -Interface sind referenzgezählt und vertragen sich schlecht mit aus dem Programm aufgerufenem destroy(), speziell die Kombination TComponent/COM-Interface ist ein Albtraum. CORBA-Interface haben diesen Nachteil nicht, da hat man alles unter Kontrolle; durch die fehlende Referenzzählung sind sie erst noch schneller.
Was ich gerne wissen würde, ist noch, ob die Prüfung auf Vorhandensein des Interfaces zeitaufwändig ist - ich vermute aber eher (und hoffe), dass das nicht der Fall ist.
Die Suche in den Tabellen ist aufwendig. CORBA hat den Vorteil, dass als ID ein beliebiger auch kurzer String verwendet werden kann, der lediglich in der Applikation einmalig sein muss. MSEide erzeugt solche ID's mit RightClick-'Insert UID'.
Schneller als die Tabellensuche zur Laufzeit ist Typenkonvertierung zur Kompilierzeit wenn der Klassentyp bekannt ist.
Code: Alles auswählen
type
{$interfaces corba}
itest = interface ['AA']{0} //ID not used in example.
procedure test();
end;
ttest = class(itest)
protected
procedure test();
end;
[...]
var
t1: ttest;
[...]
itest(t1).test();
Dabei wird die ID nicht benötigt. Ist die Tabellensuche unumgänglich, empfehlen sich ID-Konstanten in der Form nummer.framework.
Code: Alles auswählen
const
id_test = 'AA.braunbaer';{0}
type
{$interfaces corba}
itest = interface [id_test]
procedure test();
end;
In MSEgui liegen alle ID's zentral in der Datei lib/common/kernel/mseinterfaces.pas.
Die Tabellenabfrage ist auch in der Form
Code: Alles auswählen
var
t1: ttest;
intf1: itest;
[...]
if t1.getinterface(itest,intf1) then begin
intf1.test();
end;
möglich.
-
- Beiträge: 369
- Registriert: Do 8. Jun 2017, 18:21
- OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10, FPC 3.2.0
- CPU-Target: 64Bit
- Wohnort: Wien
Re: Implementiert eine Komponente ein Interface?
Momentan funktioniert es mit den standard COM Interfaces. Ich werde aber Corba auch noch ausprobieren. Wenn ich es richtig verstehe, muss ich nur in allen Units, die so ein Interface verwenden, {$interfaces corba} vor die erste Verwendung/Deklaration einfügen, und dann kann ich, wenn ich will, statt der GUID auch einen kürzeren Namen verwenden.
-
- Beiträge: 2013
- Registriert: Do 16. Okt 2008, 10:22
- OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
- CPU-Target: x86,x64,ARM
Re: Implementiert eine Komponente ein Interface?
Ja, und es gibt keine Probleme mit Referenzzählung.
-
- Beiträge: 1912
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
Re: Implementiert eine Komponente ein Interface?
So ne ganz dumme frage, warum verwendet man nicht einfach den is operator?
Das macht intern zwar auch den kram mit den GUIDs aber als entwickler muss man sich nicht um die guids kümmern. Ledeglich wenn man ein Interface schreibt einmal in Lazarus STRG+SHIFT+G drücken um die GUID zu generieren, danach kann man die GUID direkt wieder vergessen.
Der as Operator würde im notfall auch eine Exception werfen wenn die Klasse das Interface nicht implementiert. Daher kann man auch einfach mit einem try except arbeiten
Code: Alles auswählen
if MyObj is ISomeInterface then
(MyObj as ISomeInterface).SomeInterfaceMethod;
Das macht intern zwar auch den kram mit den GUIDs aber als entwickler muss man sich nicht um die guids kümmern. Ledeglich wenn man ein Interface schreibt einmal in Lazarus STRG+SHIFT+G drücken um die GUID zu generieren, danach kann man die GUID direkt wieder vergessen.
Der as Operator würde im notfall auch eine Exception werfen wenn die Klasse das Interface nicht implementiert. Daher kann man auch einfach mit einem try except arbeiten
Code: Alles auswählen
try
ifVar := SomeObj as ISomeInterface
except
on E: Exception do
// kein ISomeInterface typ
end;
-
- Beiträge: 369
- Registriert: Do 8. Jun 2017, 18:21
- OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10, FPC 3.2.0
- CPU-Target: 64Bit
- Wohnort: Wien
Re: Implementiert eine Komponente ein Interface?
Versteh ich auch nicht. Es wäre die intuitiv naheliegendste Variante, und es war eigentlich das erste Konstrukt, das ich versucht habe - erst nachdem der Compiler das nicht wollte, habe ich angefangen, die Doku durchzustöbern, und dann den Thread hier eröffnet.
-
- Beiträge: 1912
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
Re: Implementiert eine Komponente ein Interface?
braunbär hat geschrieben:Versteh ich auch nicht. Es wäre die intuitiv naheliegendste Variante, und es war eigentlich das erste Konstrukt, das ich versucht habe - erst nachdem der Compiler das nicht wollte, habe ich angefangen, die Doku durchzustöbern, und dann den Thread hier eröffnet.
Du musst eine guid erstellen (Strg+Shift+g in laz) damit müsste es funktionieren
-
- Beiträge: 2013
- Registriert: Do 16. Okt 2008, 10:22
- OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
- CPU-Target: x86,x64,ARM
Re: Implementiert eine Komponente ein Interface?
Warf hat geschrieben:So ne ganz dumme frage, warum verwendet man nicht einfach den is operator?
Performance?
Code: Alles auswählen
if MyObj is ISomeInterface then
(MyObj as ISomeInterface).SomeInterfaceMethod;
Das macht intern zwar auch den kram mit den GUIDs aber als entwickler muss man sich nicht um die guids kümmern. Ledeglich wenn man ein Interface schreibt einmal in Lazarus STRG+SHIFT+G drücken um die GUID zu generieren, danach kann man die GUID direkt wieder vergessen.
Das ist hier auch nicht anders:
Code: Alles auswählen
if t1.getinterface(itest,intf1) then begin
intf1.test();
end;
und die Tabellenabfrage geschieht nur einmal. Wenn man CORBA statt COM-Interfaces einsetzt gibt es zusätzlich keinen Overhead durch die Referenzzählung.
Der as Operator würde im notfall auch eine Exception werfen wenn die Klasse das Interface nicht implementiert. Daher kann man auch einfach mit einem try except arbeitenCode: Alles auswählen
try
ifVar := SomeObj as ISomeInterface
except
on E: Exception do
// kein ISomeInterface typ
end;
Hier ist die Performance noch schlechter. Verfolge mal mit dem Debugger was so alles passiert. Vor allem das Auslösen einer exception ist sehr aufwendig aber auch das einfache try/except ist nicht kostenlos. In MSElang verwende ich "Zero-cost exception handling" aber auch dort ist nur der exceptionlose Durchlauf durch die Exception-Strukturen ohne Zusatzaufwand und die EXE wird durch die abgelegten Verwaltungsinformationen grösser.
-
- Lazarusforum e. V.
- Beiträge: 394
- Registriert: Sa 15. Mai 2010, 13:46
- CPU-Target: 64 bit
- Kontaktdaten:
Re: Implementiert eine Komponente ein Interface?
So ne ganz dumme frage, warum verwendet man nicht einfach den is operator?
Hallo, hier ein Beispiel, was passiert, wenn man keine IDs für die Interfaces festgelegt hat:
Code: Alles auswählen
program interfaceproblem;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, sysutils;
type
{$interfaces corba}
IInt1 = interface
procedure test1;
end;
IInt2 = interface
procedure test2;
end;
TObj1 = class(IInt1)
procedure test1;
end;
TObj2 = class(TObj1, IInt2)
procedure test2;
end;
procedure TObj1.test1;
begin
writeln('test 1 called');
end;
procedure TObj2.test2;
begin
writeln('test 2 called');
end;
procedure test;
var
int : IInt1;
begin
writeln('start test');
int := TObj2.create as IInt1;
int.test1; // ERROR: prints test 2 called
end;
begin
test;
end.
Ich hatte jüngst ein schwer auffindbares Bug in einem Programm mit diversen Interfaces. Die Is und As-Operatoren funktionierten zwar, aber der Aufruf der Interface-Methoden ging nicht so richtig. Dann habe ich entdeckt, dass ich die GUID vergessen hatte
Hier im Beispiel überschreibt die Implementierung von IInt2 offenbar irgendwie die Memory Tabelle von IInt1. Das geht auch, wenn die Methoden vollkommen verschiedene Parameter verwenden und dann sucht man den Fehler
Wieso kompiliert der Code im Beispiel überhaupt ohne Fehlermeldung?