![]() |
Delphi-Version: 11 Alexandria
Generische Interface-GUIDs
Moin Loide,
habe das jetzt schon in vielen Gruppen diskutiert und alle fanden den Vorschlag eigentlich wirklich gut und wichtig. Was wir brauchen sind einzigartig generierte GUIDs für generische Interfaces! Was mich wirklich jedes mal abnervt ist folgendes Szenario: Es ist ein gewöhnlicher Tag. Draußen zwitschern die Vögel, die Sonne scheint. Man sitzt so am PC und denkt sich nichts böses. Gut gelaunt deklariere ich ein generisches Interface, und will es mit verschiedenen Typparametern in einer Funktion benutzen. Was nicht geht, zumindest nicht richtig, weil beide Interfaces die gleiche VMT und die gleiche GUID benutzen, und somit weder von einander unterscheidbar, noch die Methoden des zweiten, dritten, ... Interfaces aufrufbar. Also, von der Wahrheit eingeholt und vor der Sinnlosigkeit des Lebens erneut resignierend, deklariere ich einzeln n Ableitungen des Interfaces mit Typenspezifikationen. Dabei könnte es so einfach sein. Eine Syntax wie diese hier könnte uns das Leben enorm erleichtern, und die Wirtschaft durch Zeiteinsparung bei der Entwicklung weit voranbringen:
Delphi-Quellcode:
Das Keyword geninterface habe ich einfach mal an dispinterface angelehnt und frei erfunden, bietet sich aber an.
type
IGenItf<T> = geninterface // Keine GUID hier, denn die wird automatisch erzeugt function Foo: T; procedure Poo; end; Dann könnte man einfach folgendes schreiben:
Delphi-Quellcode:
Das mag jetzt nicht nach viel Ersparnis an Code aussehen, bei einigen Beispielen ist das aber äußerst beträchtlich.
type
TImplObject = class(TInterfacedObject, IGenItf<Integer>, IGenIntf<String>) // Implementierungen function Int_Foo: T; procedure Int_Poo; function Str_Foo: T; procedure Str_Poo; // Delegationen function IGenItf<Integer>.Foo = Int_Foo; procedure IGenItf<Integer>.Poo = Int_Poo; function IGenItf<String>.Foo = Str_Foo; procedure IGenItf<String>.Poo = Str_Poo; end; Was haltet ihr davon? |
AW: Generische Interface-GUIDs
Und bei jeden Full Build kommt eine andere GUID bei raus? :roll:
|
AW: Generische Interface-GUIDs
Es könnte auch sein, dass garkeine GUID generiert wird und die einfach nur 0000-000-00000-0000.... ist
Mir war so, als wenn der Compiler bei Interfaces "ohne" GUID eh gewisse Dinge verbietet / nicht kompilert, wie z.B. die Verwendung von IS und AS. Somit wäre dabei die GUID dann eh egal, wenn sie nie verwendet würde. Gab es bezüglich Generics bei Interfaces nicht hier mal irgendwo eine größere Diskusion/Thread? Wenn man die GUID angibt, dann würde doch jede Ableitung die Gleiche GUID bekommen, was so auch nicht super gut wäre. |
AW: Generische Interface-GUIDs
Poste doch einfach den Link zum Featurerequest, damit auch jemand dafür voten kann. Ansonsten passiert da ohnehin nichts, egal wie viel es in Foren diskutiert wird.
Automatisch generierte GUIDs würden jedenfalls nur einen Teil der Probleme lösen. Ich hatte das Thema GUIDs bei generischen Interfaces auch schon, wenn auch mit anderem Hintergrund. Mir fällt aber schlicht keine wirklich sinnvolle Lösung dafür ein. Deshalb hatte ich dazu auch keinen Featurerequest geschrieben bzw. erst einmal danach gesucht. Nebenbei gibt es ähnliche Themen im Hinblick auf Casts usw. ja auch bei anderen Sprachen wie C#, wo man für generische Typen kein Marshalling für interop usw. hat. |
AW: Generische Interface-GUIDs
Berücksichtig man den Fakt, dass in Delphi zwei an verschiedenen Stellen deklarierte TList<string> auch formell zwei unterschiedliche Typen sind, sehe ich da noch einen sehr langen Weg bis sowas realisiert werden könnte.
|
AW: Generische Interface-GUIDs
Mach halt einfach kein supports auf nen generisches interface
Zitat:
|
AW: Generische Interface-GUIDs
Jupp, Generics werden beim Compilieren über eine Art globalen Cache verwaltet.
Wurde einmal ein generic implementiert/verwendet, und kommt an anderer Stelle nochmal "neu" vor, dann wird die bereits bestehende Deklaration verwendet. z.B. TArray<irgendwas> in einer Unit und TArray<irgendwas> in einer anderen Unit sind somit identisch. Im Gegensatz dazu sind "array of irgendwas" an beiden Stellen "neue" deklarationen und somit jeweils "eigene" Typen. In einer anderen EXE/DLL natürlich nicht mehr, weil neues/anderes Compilat. |
AW: Generische Interface-GUIDs
Zitat:
|
AW: Generische Interface-GUIDs
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Genau deshalb sind GUIDs ja so wichtig. |
AW: Generische Interface-GUIDs
Zitat:
|
AW: Generische Interface-GUIDs
Oh ja, ich habe das k vor dem einen überlesen. :pale: Wird Zeit den Kopf zu lüften... :-D
|
AW: Generische Interface-GUIDs
Delphi-Quellcode:
type
IGenItf<T> = geninterface // Keine GUID hier (oder doch, aber egal) function Foo: T; procedure Poo; end; type IIntItf = interface(IGenItf<Integer>) ['{123.......}'] end; IStrItf = interface(IGenItf<String>) ['{456.......}'] end; TImplObject = class(TInterfacedObject, IIntItf, IStrIntf) ... |
AW: Generische Interface-GUIDs
Wenn wir hier schon bei Wünsch dir was sind, dann wäre dies hier etwas weniger invasiv:
Delphi-Quellcode:
type
IGenItf<T> = interface ['<AutoGUID>'] function Foo: T; procedure Poo; end; |
AW: Generische Interface-GUIDs
Rein syntaktisch ist das doch eigentlich falsch. :stupid:
Attribute stehen doch vor dem, was sie beschreiben und (leider) nicht dahinter.
Delphi-Quellcode:
type
[AutoGUID] IGenItf<T> = interface function Foo: T; procedure Poo; end; [GUID('{00000000-0000-0000-0000-000000000000}')] IGenItf<T> = interface function Foo: T; procedure Poo; end; |
AW: Generische Interface-GUIDs
Zitat:
Oder gibt es Fälle wo man wirklich keine haben will? |
AW: Generische Interface-GUIDs
Na viel Spaß sobald der Erste versucht sich das über Modulgrenzen (EXE, DLL) hinweg in andere Sprachen/Framework zu übergeben und die Gegenseite eher nicht so glücklich mit dynamischen GUIDs ist.
|
AW: Generische Interface-GUIDs
Zitat:
|
AW: Generische Interface-GUIDs
Zitat:
Solange nicht klar definiert ist, welche GUID zu welchem konkreten Typ dynamisch zugeordnet wird, klappt das ganze nicht. Deshalb könnte ich mir nur eine im Projekt gepflegte Tabelle oder etwas ähnliches vorstellen, ähnlich dem TLB-Editor, mit speziellen Textdateien, die die Zuordnungen anhand des voll qualifizierten Typnamens, sprich inkl. Unitname, enthalten. Ich kann mir aber ehrlich gesagt nicht so recht vorstellen, dass Embarcadero ein solches Feature implementiert, wenn es nicht wirklich viele, ganz viele, Votes für einen entsprechenden Featurerequest gibt. |
AW: Generische Interface-GUIDs
Delphi-Quellcode:
const
// Die Konstante kann auch aus einer gemeinsamen UNIT oder .INC kommen. // resourcestring anstatt const geht aber nicht, weil Konstante eine GUID und kein String sein muß. MyGUID: TGUID = '{BE3C619C-001C-490E-A377-C08D51E18C0C}'; type IGenItf<T> = interface [MyGUID] function Foo: T; procedure Poo; end;
Delphi-Quellcode:
type
IGenItf<T> = interface [{$INCLUDE 'MyGUID.inc'}] // '{BE3C619C-001C-490E-A377-C08D51E18C0C}' function Foo: T; procedure Poo; end;
Delphi-Quellcode:
nur Nachfolgendes geht natürlich nicht
type
IGenItf<T> = interface {$INCLUDE 'MyGUID.inc'} // ['{BE3C619C-001C-490E-A377-C08D51E18C0C}'] function Foo: T; procedure Poo; end;
Delphi-Quellcode:
type
IGenItf<T> = interface ['{$INCLUDE MyGUID.inc}'] // {BE3C619C-001C-490E-A377-C08D51E18C0C} function Foo: T; procedure Poo; end;
Delphi-Quellcode:
type
IGenItf<T> = interface ['{{$INCLUDE MyGUID.inc}}'] // BE3C619C-001C-490E-A377-C08D51E18C0C function Foo: T; procedure Poo; end; |
AW: Generische Interface-GUIDs
Zitat:
Bei generische interfaces über Modulgrenzen hinweg - selber Schuld wer sowas dort verwenden will. |
AW: Generische Interface-GUIDs
Zitat:
Ich fände es schon praktisch, wenn ich das nicht über Tricks in der Schnittstelle zu C# realisieren müsste. Es funktioniert zwar, ist aber zusätzlicher Aufwand, wenn auch nicht sonderlich viel. Da ich unter C# nicht direkt in den generischen Typ casten kann, habe ich ein nicht generisches Interface plus Klasse von den generischen Typen abgeleitet. Dorthin kann ich casten, obwohl der Quellcode komplett in der Elternklasse liegt... |
AW: Generische Interface-GUIDs
Entweder reden wir total aneinander vorbei oder ...
Wenn Du ein Modul in Delphi hast und dort eben TList<TBla> und ein anderes Modul in C# - wie übergibst Du dann sowas? Ich kenne Übergaben nur mit OLE wobei die Typen für die Schnittstelle in einer IDL definiert werden. Ich wüsste nicht ob und wie da Generics überhaupt gehen. |
AW: Generische Interface-GUIDs
Rein technisch sind die Generics oder nicht vollkommen egal-
Du könntest auf einer Seite auch eine generisches Interface haben und auf der anderen Seite ein Normales ... sie müssen nur die gleiche GUID haben und eine Tabelle von Methoden, die nichtmal gleich heißen müssen, weil es ist nur der Index wichtig, also die Reihenfolge/Anzahl und die Parameter-Definition und das was diese Methoden machen sollen. Das Interface ist nur ein Zeiger. Zum Prüfen und Konvertieren mit einer GUID ... will man nichts prüfen und auch nicht in ein anderes Interface casten, dann ist die GUID egal. |
AW: Generische Interface-GUIDs
Zitat:
Auf diese Weise kann ich mir einfach z.B. aus einer geladenen C#-DLL ein Interface IExample holen und die Methode Run aufrufen. Delphi:
Delphi-Quellcode:
C#:
if TBlub.TryGet<IExample>(Example) then
Example.Run(42);
Code:
Anders als mit anderen Lösungen brauche ich dafür keine Registrierung der Assembly oder ähnliche Voraussetzungen. Es funktioniert komplett portabel, sofern die verwendete .NET Version installiert ist. Man muss bei den Interfaces ein paar Regeln, z.B. für Strings (die Marshalling-Attribute brauchen), beachten, aber ansonsten ist das recht intuitiv nutzbar.
if (Blub.TryGet<IExample>(ref Example))
{ Example.Run(42); } Auf Delphi-Seite klappt das auch mit generischen IList<T> Interfaces problemlos. Auf C#-Seite muss ich dafür wie schon geschrieben eine nicht-generische Klasse ableiten, aber auch da ist es mit wenigen Zeilen erledigt, die ich zudem nur kopieren und mit dem konkreten Typ versehen muss. Aber ich glaube das führt hier zu weit... Zitat:
|
AW: Generische Interface-GUIDs
Der Beitrag ist nun schon älter, aber falls darüber mal jemand stolpert, möchte ich ergänzen, dass ich die angesprochene Funktionalität nun in neu geschriebener Form veröffentlicht habe:
![]() |
AW: Generische Interface-GUIDs
Zitat:
|
AW: Generische Interface-GUIDs
Zitat:
Delphi-Quellcode:
bzw.
IGenItf<string>
Delphi-Quellcode:
natürlich immer dieselbe GUID bekommt - wobei ich das als nur schwer stabil umzusetzen einschätze. Sollte die Auto-GUID bei jedem Kompilat anders sein, schließt das natürlich den beschriebenen Anwendungsfall aus.
IGenItf<Integer>
|
AW: Generische Interface-GUIDs
AutoGUIDs kann man natürlich immer nur innerhalb des selben Compilates benutzen.
* Zur Laufzeit bleibt diese GUID dann natürlich unverändert. * Zwischen zwei Compilierungen könnte sie sich ändern, außer man nutzt z.B. sowas wie eine Cache (Delphi könnte sich diese GUIDs z.B. für Pfad zur Unit, zusammen mit dem implementierten TypeName merken) * aber egal ... debuggen tut man eh nur ein Compilat und hat doch normal keine Verbindung zu anderen Debugsessions |
AW: Generische Interface-GUIDs
Möglich wäre das schon, ich hatte dazu ja schon etwas geschrieben. Der Compiler müsste eine Textdatei erstellen, die diese Zuordnung enthält und auch vorher nachschauen, ob eine Definition bereits enthalten ist. Da würde ja die Zuordnung über den kompletten Namen des generischen Interfacetyps reichen. Dann würde man diese generieren und erweitern lassen und genauso wie alles andere einchecken.
Das wäre meiner Meinung nach auch der einzige wirklich gangbare Weg, denn: - Nur so bleiben die GUIDs für einen konkreten Typ stabil - Nur so kann der Compiler diese über mehrere Kompilate usw. hinweg stabil halten - Und nur so kann man diese GUIDs dann als Liste für andere Sprachen wie C++ veröffentlichen Der Implementierungsaufwand wäre vermutlich auf diesem Weg nicht einmal besonders hoch. Ich habe in der Zwischenzeit eine RTTI-basierte Lösung ins Auge gefasst. Vielleicht komme ich im Zuge des AppCentral-Projekts doch noch dazu, mir das einmal anzuschauen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:58 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