Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi TypeInfo über IID oder Klasse (und RTTI) (https://www.delphipraxis.net/50161-typeinfo-ueber-iid-oder-klasse-und-rtti.html)

choose 21. Jul 2005 11:28


TypeInfo über IID oder Klasse (und RTTI)
 
Hallo zusammen,

nach meiner Auffassung besitzt jedes Interface mit IID, das von einer Klasse implementiert wird auch TypInfoformationen, die über den Aufruf von
Delphi-Quellcode:
TypeInfo(IAnInterfaceName)
abgefragt werden können. Sieht man sich das Kompilat genauer an, ist eine "magische" Adresse zu erkennen, an der eine Referenz auf die Daten abgelegt ist. Diese Zahl wird auch bei Aufrufen von TypeInfo bei anderen Typen vom Compiler generiert und kann meines Wissens nicht anders als eben über diese Funktion/Operator erlangt werden.
Objekte und Klassen bieten mit TObject.ClassInfo darüber hinaus auch zur Laufzeit die Möglichkeit, auf dieser Daten zuzugreifen, so dass Konstruktue wie
Delphi-Quellcode:
function GetUnit(const AnObject: TObject): string;
begin
  Result := GetTypeData(AnObject.ClassInfo).UnitName;
end;
u.a. erlauben, den Unitbezeichner der Klasse eines Objekts zu ermitteln (sofern die Klasse mit Typinformationen kompiliert wurde, siehe OH).




Mein Problem ist etwas anders gestaltet.
Ich suche nach einer Möglichkeit, die erste Referenz auf ein TTypeInfo-Record des Interfaces mit einem IID einer Klasse oder seinem Vorfahren zu erlangen.

Delphi-Quellcode:
type
  IMyInterface = interface
  ['AnIID']
    procedure AMethod;
  end;

  TMyClass = TInterfacedObject(IMyInterface)
    procedure AMethod;
  end;

function GetTypeInfoOfFirstInterface(const AClass: TClass): PTypeInfo;
Der Rückgabewert von GetTypeInfoOfFirstInterface sollte im skizzierten Fall dasselbe Resultat bringen wie
Delphi-Quellcode:
Assert( TypeInfo(IMyInterface)=GetTypeInfoOfFirstInterface(TMyClass) );
Über TObject.GetInterfaceTable bekomme ich für jedes durch eine Klasse implementierte Interface mit IID eine Referenz auf das Record TInterfaceEntry mit
Delphi-Quellcode:
type
  TInterfaceEntry = packed record
    IID: TGUID;
    VTable: Pointer;
    IOffset: Integer;
    ImplGetter: Integer;
  end;
ich kann aber leider nicht entdecken, ob ich auf diesem Weg an die Typinformationen herankomme.
Selbstverstädnlich würde sich auch eine Technik anbieten, bei der die Typinformationen (sofern vorhanden) über einen IID ermittelt werden.

Weiß jemand von Euch eine Lösung?

negaH 21. Jul 2005 14:50

Re: TypeInfo über IID oder Klasse (und RTTI)
 
nein über diesen Weg geht das leider nicht da der Compiler in den RTTI einer Klasse über die PInterfaceTable nur die durch die Klasse implementierten Interface die Infos ablegt. Der RTTI Record über ein IInterface ist dabei was komplett anderes und das einzigst Gemeinsamme in beiden RTTI-Records ist die GUID.

Ich habe hier im Forum mal einen "inoffiziellen" Weg gepostet, samt Source, wie man aber über die TypInfos eines kompletten Modules iterieren kann. Mit dieser Methode wäre es nun möglich eine Funktion zu coden die zu einer GUID die TypeInfo dieses IInterfaces ermittelt.

Allerdings dürfte das garnicht notwendig sein :)

Delphi-Quellcode:
function HasInterface(AClass: TClass; ATypeInfo: PTypeInfo): Boolean;
begin
  Result := (ATypeInfo <> nil) and (ATypeInfo.Kind = tkInterface) and
            (AClass <> nil) and (AClass.GetInterfaceEntry(GetTypData(ATypeInfo).GUID) <> nil);
end;


procedure Test;
begin
  if HasInterface(TypeInfo(IMyInterface), TMyClass) then ...
end;
Wie man aber unschwer erkennen kann ist dieser Weg im Grunde "doppelgemoppelt" denn so ginge es viel einfacher

Delphi-Quellcode:
procedure Test;
begin
  if TMyClass.GetInterfaceEntry(IMyInterface) <> nil then
    with TypeInfo(IMyInterface) do
end;
Da die "function TypeInfo()" ein Compiler Magic ist, also schon zur Kompilierungszeit wird TypeInfo() aufgelösst und im fertigen Code steht nur noch ein "Zeiger ins Codesegment", gibt es eh keinen Weg die ganze Sache dynamisch zur Laufzeit zu machen.

Gruß Hagen

barf00s 21. Jul 2005 14:53

Re: TypeInfo über IID oder Klasse (und RTTI)
 
könnt ihr nich auch einfach

if Supports(TDeineClass, IDeinInterface) then ...

nehmen?

choose 21. Jul 2005 15:03

Re: TypeInfo über IID oder Klasse (und RTTI)
 
Hallo Hagen :),

Deinen Beitrag im Thread IsObject / IsClass habe ich nicht vergessen. Diese Variante ist für mich leider nur ein "Notnagel", weil er nicht auf dokumentierten Routinen basiert. Ich befürchte, dass die Routinen so in Zukunft nicht länger funktieren.

Hast Du eine Ahnung, ob das mit Delphi2005 gegen Win32 klappt?

choose 21. Jul 2005 15:16

Re: TypeInfo über IID oder Klasse (und RTTI)
 
Hallo barf00s und nochmal Hagen,

Routinen der Art Supports und HasInterface beantworten wie skizziert die folgende Frage
Zitat:

Unterstützt eine gegebene Klasse ein gegebenes Interface?
mich interessiert aber folgendes:
Zitat:

Welche Typinformation hat das erste (unbekannte) Interface, das eine gegebene Klasse unterstützt?
Die Frage nach dem Interface selbst sowie dessen IID ließe sich mit TObject.GetInterfaceTable lösen, von dort komme ich aber leider nicht auf eine Referenz von TTypeInfo.

Aus meiner aktuellen Perspektive bleibt keine andere Möglichkeit, als mit Hagens Routine (s.o.) alle Typinformationen nach einem Interfacetyp mit einem übereinstimmenden IID zu durchsuchen (bzw. in einer suchbaren Struktur zu registrieren).

Ich würde aber gerne eine... sagen wir... Delphi-artige Lösung verwenden ;), die wie AnObject.ClassName auch die nächsten 9 Versionen von Delphi Bestand haben wird und gleichfalls auf Essenziellem beruht, so das ggf. sogar eine spätere Portierung nach .net in Betracht kommt.

barf00s 21. Jul 2005 15:20

Re: TypeInfo über IID oder Klasse (und RTTI)
 
darf man fragen was du überhaupt mit diesem dingen bezwecken willst?

negaH 21. Jul 2005 15:24

Re: TypeInfo über IID oder Klasse (und RTTI)
 
@Barfoos:

schau dir mal in SysUtils.pas die Implementation von Supports() genauer an. Es ginge also schon aber du benötigst ein alloziertes Object statt einer Klasse und wenn das Object dieses Interface unterstützt wird intern schon eine neue Refernez auf diese Interface gezogen. Das bedeutet der Code von Supports() ist keine passive Abfrage ob eine Klasse/Object ein Interface unterstützt sondern im gegenteil eine aktive Abfrage indem testweise das Interface angefordert wird.

@Choose: ich glaube schon das Delphi auch weiterhin meinen Trick unterstützen wird. Immerhin handelt es sich hier um langjähriges und altbewährtes Vorgehen innerhalb des Compilers. Sollte sich daran was ändern so würde das für Borland einen immensen Aufwand an Änderungen im Compiler bedeuten.
Man kann ja per Compiler Defines die entsprechende Compilerversion in meinem Source abfragen und falls der Source dann auf einer neuen Version compiliert wird gibt man im Source eine Fehlermeldung aus. Man muß also dann erstmal einen kleinen Testcode mit der neuen Version laufen lassen, feststellen ob's noch funktioniert und dann gegebenfalls die neue Version in die Compiler Defines einbauen. So stellt man auf alle Fälle sicher das man diesen sensiblen Code nicht ohne Warnungen verwendet.

Ich vermute mal das dein obiger Beispiel Source nur eine verkürzte Variante darstellt, d.h. das du im fertigen Source eben dynamisch zur Laufzeit diese TypInfo-Überprüfungen durchführen möchtest (anders macht deine Frage eigentlich keinen Sinn). Nun, und in diesem Szenario sehe ich nur den Weg über meine Funktion zur Iteration der TypInfos.

Gruß Hagen

negaH 21. Jul 2005 15:33

Re: TypeInfo über IID oder Klasse (und RTTI)
 
Ich würde erstmal mit meinem Code arbeiten. Du benutzt eine TList in der du alle @TypeInfo vom Type tkInterface sammelst. Diese TList ist mit einer eigenen Sort Callback sortiert nach der GUID der GetTypeData(PTypeInfo).GUID. So kannst du nach der Erzeugung dieser TList sehr schnell nach der GUID darin suchen, ebenfalls mit einer speziellen Suchfunktion. Das alles ausgelagert in eine eigene Unit die per Compiler Defines auf die getesteten Delphi Versionen geschützt wurde.

Gruß Hagen

choose 21. Jul 2005 15:37

Re: TypeInfo über IID oder Klasse (und RTTI)
 
Hallo barf00s,

ich ergänze gerade mein Framework zur Bei Google suchenDependency Injection um die Möglichkeiten eines Plug-In-Frameworks eines Drittherstellers, das pro Modul eine Liste von Fabriken bereithält, die neben der Fabrikation selbst leider nur eine Referenz auf die (dynamisch nachgeladene) Klasse anbieten. Um den Abhängigkeitsgraphen bei der Injektion traversieren und rekursiv lösen zu können nutzt die Implementation eines Containers Typinformationen, da injizierte Abhängigkeiten auch auf Basis von Klassen oder anderen Typen formuliert werden- und eben nicht nur Interfaces.
Trotzdem beschreiben viele der Container Abhängigkeiten zu speziellen Interfaces (Services), die ihrerseits nun durch das Plug-In-Framework nachgeladen werden. Weil ich das Plug-In-Framework des Drittherstellers nicht verändern und schon gar nicht in den Registraturmachnismus dieser Plug-ins eingreifen möchte, bleibt zur Ermittlung des (ersten, es handelt sich um einen Service) unterstützen Interfacetyps aus meiner Sicht nur die Möglichkeit, sie aus der Klassenreferenz zu extrahieren.

Oder übersehe ich etwas? :gruebel:

choose 21. Jul 2005 15:50

Re: TypeInfo über IID oder Klasse (und RTTI)
 
Hallo Hagen,

Zitat:

Zitat von negaH
schau dir mal in SysUtils.pas die Implementation von Supports() genauer an. [..] du benötigst ein alloziertes Object statt einer Klasse [..]

ich weiß, dass Du auf den D5-Compiler schwörst, aber in meinem D7 konnte ich (wie barf00s?) die folgende überladene Variante von Supports finden, die ich auch gerne von Zeit zu Zeit einsetze:
Delphi-Quellcode:
function Supports(const AClass: TClass; const IID: TGUID): Boolean;
begin
  Result := AClass.GetInterfaceEntry(IID) <> nil;
end;
Zitat:

Zitat von negaH
Ich vermute mal das dein obiger Beispiel Source nur eine verkürzte Variante darstellt, d.h. das du im fertigen Source eben dynamisch zur Laufzeit diese TypInfo-Überprüfungen durchführen möchtest

Ganz genau, und ohne Deinen Code als "Ass im Ärmel" hätte ich mich nie so weit in diese Richtung hinausgelehnt ;) Trotzdem habe ich dabei gemischte Gefühle.

Hat jemand die Anwendbarkeit der Routinen zur Ermittlung aller Typifnormationen pro Modul für Delphi2005 gegen Win32 verifizieren/falsifizieren können?

negaH 21. Jul 2005 16:19

Re: TypeInfo über IID oder Klasse (und RTTI)
 
Zitat:

ich ergänze gerade mein Framework zur Dependency Injection um die Möglichkeiten eines Plug-In-Frameworks eines Drittherstellers, das pro Modul eine Liste von Fabriken bereithält, die neben der Fabrikation selbst leider nur eine Referenz auf die (dynamisch nachgeladene) Klasse anbieten. Um den Abhängigkeitsgraphen bei der Injektion traversieren und rekursiv lösen zu können nutzt die Implementation eines Containers Typinformationen, da injizierte Abhängigkeiten auch auf Basis von Klassen oder anderen Typen formuliert werden- und eben nicht nur Interfaces.
Trotzdem beschreiben viele der Container Abhängigkeiten zu speziellen Interfaces (Services), die ihrerseits nun durch das Plug-In-Framework nachgeladen werden. Weil ich das Plug-In-Framework des Drittherstellers nicht verändern und schon gar nicht in den Registraturmachnismus dieser Plug-ins eingreifen möchte, bleibt zur Ermittlung des (ersten, es handelt sich um einen Service) unterstützen Interfacetyps aus meiner Sicht nur die Möglichkeit, sie aus der Klassenreferenz zu extrahieren.

Oder übersehe ich etwas?
Ähm ja ? kannst du das bitte auf deutsch posten ?

Bisher habe ich verstanden das du eine externe Schnittstelle in deine Anwendung anbieten nöchtest. Man kann also nachladbare Plugins erzeugen die in deinen Framework eingebunden werden. Schön. Aber wozu so umständlich und warum "Dependency Injection" -> "Abhängigkeits-Einspritzung" ? was soll das sein ?

Normalerweise designe ich die Schnittstelle für die Plugins aus Sicht der Erfordernissen der Anwendung die diese Schnittstelle zur Verfügung stellen will, nicht umgekehrt. An diese Schnittstelle haben sich Plugins zu halten und IN dieser Scnittstelle gäbe es dann alle nötigen Methoden um an diese Infos ranzukommen.
Davon mal abgesehen halte ich die Idee das die Plugin-Applikation tiefgehende Zugriffe auf die Implementation der Plugins ansich hat als sehr schlecht. Das widerspricht dem Black-Box-Prinzip.

Naja, und bei Google finde ich unter "Dependency Injection" nur JAVA Kram und ich kann heut noch nicht verstehen warum sich echte Programmierer wie wir sich JAVA als Vorbild nehmen ;)

Gruß Hagen

negaH 21. Jul 2005 16:23

Re: TypeInfo über IID oder Klasse (und RTTI)
 
Delphi-Quellcode:
function Supports(const AClass: TClass; const IID: TGUID): Boolean;
begin
  Result := AClass.GetInterfaceEntry(IID) <> nil;
end;

Super also so wie ich's oben schon benutzt hatte. Ich halte diese Implementation in D7 für schlecht bzw. nicht Bulletproof, es fehlt die Abfrage (AClass <> nil). (schonwieder haben die Borländer geschlafen, das nimmt mit jeder Delphi Version weiter zu)

Gruß Hagen

choose 21. Jul 2005 16:59

Re: TypeInfo über IID oder Klasse (und RTTI)
 
Hallo Hagen,

Zitat:

Zitat von negaH
was soll das [dependency injection] sein ?

puh... Das haben andere Leute (auch unter dem Namen Bei Google suchenInversion of Control Container) viel besser erklärt, als ich das wohl hier könnte. Leider fehlt mir dazu im Augenblick die Zeit, das genauer vorzustellen, gehe aber davon aus, dass die inzwischen gut verwendbare Lösung "eines Tages" der Öffentlichkeit vorgestellt/zur Verfügung gestellt wird.

Zitat:

Zitat von negaH
Normalerweise designe ich die Schnittstelle für die Plugins aus Sicht der Erfordernissen der Anwendung die diese Schnittstelle zur Verfügung stellen will, nicht umgekehrt.

Klingt vernüftig! Ich habe hier auf der anderen Seite ein System, in das ich -salop ausgedrück- "alles reinwerfe, was ich habe" und heraus kommt ein konfiguriertes System. Wenn ein Fenster eine Datenbankverbindung benötigt, macht es das durch entspr. Komponenten kenntlich, wie sonst. Benötigt eine ordinäre Klasse diese Verbindung, deklariert es das zB per Published Property, die nicht gespeichert wird, sollen nicht veränderbare Klassen verwendet werden, die Abhängigkeiten haben, gibt es spezielle Adapter, die das Ummanteln.
Ziehe ich jetzt -sprichwörtlich- "an der Schnur" ein beliebiges Objekt heraus, wird es mit der Datenbankverbindung verknüpft, die ihrerseits zunächst erzeugt wird (? kommt darauf an, wie der zuständige Adapter das macht), die dazu zB einen Logger benötigt, der seinerseits diverse Senken unterstüzt, die ihrerseits zB eine Internetverbindung benötigen, usw. und voilá das Fenster ist erzeugt.
Die "Injektion" besteht darin, dass keine dieser Klassen beschreibt, welche konkrete Klasse wann wo erzeugt wird, um das Problem zu lösen. Stattdessen tut sie das was sie soll: Exemplare des beschriebenen Typs verwenden und nicht erzeugen.

Die Tatsache, dass nun solche "Komponenten" aus Plugins erzeugt werden, ist eher... nettes Beiwerk (oder eben auch nicht).
Ich stelle das gerne zu einem späteren Zeitpunkt genauer vor. Solange bleibt mir zu sagen: Funktioniert prima :)

Zitat:

Zitat von negaH
ich kann heut noch nicht verstehen warum sich echte Programmierer wie wir sich JAVA als Vorbild nehmen ;)

Dann würde ich mich nicht als "echten Programmierer" bezeichnen (obwohl ich mir häufig lieber die Vorbilder von Java zum Vorbild nehme). Schließlich kommt die Zauber-Routine von oben ja auch von Dir und nicht von mir ;)

negaH 21. Jul 2005 17:28

Re: TypeInfo über IID oder Klasse (und RTTI)
 
Hi Choose,

ok ich habe mir kurz einige Seiten zu dieser Thematik reingezogen und bin sehr gespannt auf deine fertige Lösung. Du würdest mir einen großen Gefallen machen wenn du mich mit einer PN über deine Veröffentlichung informierst. Das interessiert mich brennend da ich selbst bei zweimaligem Lesen des Artikels nicht verstanden habe warum man ein solches Problem über DI lösen sollte. Soweit wie ich das nämlich beurteilen kann ist das "von Hinten durch den Kopf" gedacht und meiner Meinung nach eine "programmiertechnische Seifenblase". Ich sehe und verstehe also nicht wo der Nutzen gegenüber einer "linear gedachten Lösung" ist. Bisher erscheint mir das eine Lösung zu sein die die Gunddenkansätze der OOP vollkommen vergewaltigt. Nun, um mir also ein fundiertes Urteil erlauben zu können wäre eventuell deine Delphi Umsetzung einer DI sehr hilfreich für mich (ich sage ja immer sage niemals nie ;) )

Gruß Hagen

choose 21. Jul 2005 17:48

Re: TypeInfo über IID oder Klasse (und RTTI)
 
Ich denke dran, schließlich werde ich mit hoher Wahrscheinlichkeit Deinen Code in den Teilbereich mit den Plug-ins einbauen (mit bedingter Kompilierung, versteht sich), sofern hier weder Einwände gegen die Kompatibiltät noch elegentare Vorschläge innerhalb der nächsten Tage kommen.

Zitat:

Zitat von negaH
"von Hinten durch den Kopf" gedacht [..] eine "programmiertechnische Seifenblase". [..] Bisher erscheint mir das eine Lösung zu sein die die Gunddenkansätze der OOP vollkommen vergewaltigt.

:shock: :lol: Dann muss ich bestimmt noch irgendetwas Performancesteigerndes oder kryptographisch Abgehobenes damit realisieren, damit ich Dich beeindrucken kann ;)

Auch wenn ich schon daran glaube, alle Leser mit wirren Formulierungen abgeschreckt zu haben:
Zitat:

Hat noch jemand eine Idee zur ursprünglichen Frage des Threads?

negaH 21. Jul 2005 18:12

Re: TypeInfo über IID oder Klasse (und RTTI)
 
Zitat:

Dann muss ich bestimmt noch irgendetwas Performancesteigerndes oder kryptographisch Abgehobenes damit realisieren, damit ich Dich beeindrucken kann
Nöö, deswegen sagte ich ja: sage niemals nie :) Ich glaube schon von mir behaupten zu können, das wenn ich einmal eine saubere Erklärung mit praktischem Beispiel für DI analysiert habe, ich für mich erkennen kann ob diese Technologie einen Nutzen bringen kann. Und das ganz unabhängig vom verwendeten Beispiel zur Demonstration. Deswegen ja meine Bitte an dich.

Zur eigentlichen Frage sehe ich nur drei Lösungen:

1.) entweder mit "schmutzigen" Tricks die bestehende Funktionalität um die Notwendige zu erweitern, oder
2.) Designtechnisch die Schnittstelle anders konstruieren um per se exakt die nötige Funktionalität von vornherein zu garantieren
3.) ein anderes Werkzeug, sprich Entwicklungssystem benutzen

Gruß Hagen

choose 22. Jul 2005 08:38

Re: TypeInfo über IID oder Klasse (und RTTI)
 
Hallo Hagen,

Zitat:

Zitat von negaH
1.) [..] "schmutzigen" Tricks [..]
2.) Designtechnisch [..]
3.) [..] Entwicklungssystem benutzen

wiedereinmal steht der in Delphi typische Komfort im Vordergund (sonst könnte man es ja gleich mit Java machen ;)). Für die Entwickler soll das System daher so einfach wie möglich sein und nicht etwa durch die Fülle an vorzunehmenen Einstellungen unverhältnismäßig viel Aufwand verlagern und so den Nutzen zerstören.
Aus diesem Grund werde ich im ersten Schritt wohl 1.) und in einem Folgeschritt eine Kombination aus 2.) und 3.) einsetzen. Die Delphi-IDE ist sehr anpassungsfähig und würde erlauben, die notwendigen Code-Schnipsel beim Speichern durch hinzugefügte Addins automatisch zu generieren...


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:55 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz