![]() |
Gleiche Interface-Referenzen?
n'abend,
ist es nur Zufall, oder haben abgeleitete Interfaces in den Objekten wirklich "immer" die selben Referenzen? Auch in anderen Plattformen und nicht nur im Windows.
Delphi-Quellcode:
Im Grunde geht es darum, ob bei
type
IFoo = interface ['{05C90FF9-4788-49FB-9C60-CA901F8BBEBA}'] procedure Foo; end; IBar = interface(IFoo) ['{01B62A8B-40E4-417C-AC63-F787C26DA89F}'] procedure Bar; end; IBlubb = interface ['{A35EE740-965E-4F97-9AC2-A99F165B0322}'] procedure Foo; end; TFooBar = class(TInterfacedObject, IBar, IFoo, IBlubb) procedure Bar; procedure Foo; end; procedure TForm3.FormCreate(Sender: TObject); var F: IFoo; B: IBar; X: IBlubb; begin B := TFooBar.Create as IBar; F := B; Memo1.Lines.Add(Format('$%p $%p', [Pointer(B), Pointer(F)])); F := B as IFoo; Memo1.Lines.Add(Format('$%p $%p', [Pointer(B), Pointer(F)])); F := TFooBar.Create as IFoo; B := F as IBar; Memo1.Lines.Add(Format('$%p $%p', [Pointer(F), Pointer(B)])); X := B as IBlubb; Memo1.Lines.Add(Format('$%p $%p', [Pointer(F), Pointer(X)])); end; procedure TFooBar.Bar; begin end; procedure TFooBar.Foo; begin end;
Delphi-Quellcode:
die Interfaces immer die selbe Referenz besitzen
procedure Test(Ref: IFoo);
und man dieses "Objekt" somit immer zuverlässig in Listen finden kann oder ob ich doch besser immer die interen Objekt-Referenzen vergleichen muß, bzw. ob ich zu Beginn immer das Interface geziehlt auf ein Bestimmtes casten (Supports/AS) sollte. |
AW: Gleiche Interface-Referenzen?
Es ist da doch etwas komplizierter:
Delphi-Quellcode:
Und die Lösung lautet hier:
program dp_184186;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type IFoo = interface ['{E4CA5AB6-B9DF-403C-B30B-72636041B010}'] end; IBar = interface( IFoo ) ['{6DFEAA0D-E3CA-4DCE-8450-7E54DC6DD7AC}'] end; TFoo = class( TInterfacedObject, IFoo ) end; TBar = class( TInterfacedObject, IBar ) end; TFooBar = class( TFoo, IBar ) end; TFooFooBar = class( TFoo, IFoo, IBar ) end; procedure PrintIntfRef( const RefName: string; const Ref: IInterface ); begin Writeln( Format( '%s($%p)', [RefName, Pointer( Ref )] ) ); end; procedure PrintFoo( const AFoo: IFoo ); begin PrintIntfRef( 'IFoo', AFoo ); end; procedure PrintBar( const ABar: IBar ); begin PrintIntfRef( 'IBar', ABar ); end; procedure Test; var LBar: IBar; begin Writeln( 'TBar' ); LBar := TBar.Create; PrintFoo( LBar ); // PrintFoo( LBar as IFoo ); // EIntfCastError PrintBar( LBar ); Writeln( 'TFooBar' ); LBar := TFooBar.Create; PrintFoo( LBar ); PrintFoo( LBar as IFoo ); PrintBar( LBar ); Writeln( 'TFooBar' ); LBar := TFooFooBar.Create; PrintFoo( LBar ); PrintFoo( LBar as IFoo ); PrintBar( LBar ); end; begin try Test; except on E: Exception do Writeln( E.ClassName, ': ', E.Message ); end; ReadLn; end.
Delphi-Quellcode:
procedure PrintFooAsFoo( const AFoo: IFoo );
var LFoo: IFoo; begin if Supports( AFoo, IFoo, LFoo ) then PrintIntfRef( 'IFoo', LFoo ) else PrintIntfRef( 'IFoo', AFoo ); end; |
AW: Gleiche Interface-Referenzen?
Zitat:
Ob das auch für die mobilen Plattformen gilt, kann ich dir nicht sagen, aber ist mit folgendem Code einfach herauszufinden:
Delphi-Quellcode:
var
table: PInterfaceTable; entry: PInterfaceEntry; i: Integer; begin table := TFooBar.GetInterfaceTable; for i := 0 to table.EntryCount - 1 do Writeln(GUIDToString(table.Entries[i].IID), ' ', table.Entries[i].IOffset); |
AW: Gleiche Interface-Referenzen?
Mist, dann werde ich wohl doch eine Typ-Prüfmethode Vorsoglich-Umwandlungsmethode (Supports) einbauen müssen.
Eine Tyüprüfung ala IS (
Delphi-Quellcode:
) geht ja nicht.
if not (Value is IFoo) then Value := Value as IFoo;
Bei Objekten zeigen unterschiedlich gecastete "Typen" ja immer auf die selbe Adresse und für Objekte kenn ich nichts, um den Interface-Typ hinter einem Interface festzustellen, sowas wie
Delphi-Quellcode:
.
if Value.Type = IFoo
Dachte ich kann mir die zusäztlichen Operationen sparen, welche ja wild mit der Referenzzählung und zusätzlichen Variablen rumfuchteln. Also hier nutzen die schon nicht mehr den selben Slot, außer man deklariert TFooBar so
Delphi-Quellcode:
.
class(TFoo, IBar, IFoo, IBlubb)
Da die Klasse nur intern ist, kann ich erzwingen, daß es genau so definiert wäre, aber ob der Code dann sicher wäre. :?
Delphi-Quellcode:
type
IFoo = interface ['{05C90FF9-4788-49FB-9C60-CA901F8BBEBA}'] procedure Foo; end; IBar = interface(IFoo) ['{01B62A8B-40E4-417C-AC63-F787C26DA89F}'] procedure Bar; end; IBlubb = interface ['{A35EE740-965E-4F97-9AC2-A99F165B0322}'] procedure Foo; end; TFoo = class(TInterfacedObject, IFoo) procedure Foo; end; TFooBar = class(TFoo, IBar, IBlubb) procedure Bar; end; procedure TForm3.FormCreate(Sender: TObject); var F: IFoo; B: IBar; X: IBlubb; begin B := TFooBar.Create as IBar; F := B; Memo1.Lines.Add(Format('$%p $%p', [Pointer(B), Pointer(F)])); F := B as IFoo; Memo1.Lines.Add(Format('$%p $%p', [Pointer(B), Pointer(F)])); F := TFooBar.Create as IFoo; B := F as IBar; Memo1.Lines.Add(Format('$%p $%p', [Pointer(F), Pointer(B)])); X := B as IBlubb; Memo1.Lines.Add(Format('$%p $%p', [Pointer(F), Pointer(X)])); end; procedure TFooBar.Bar; begin end; procedure TFoo.Foo; begin end; Aber vielleicht lass' ich es erstmal so und bau mir eine Methode, welche am Anfang die InterfaceTable ausslist und prüft. :gruebel: Müsste ja jedes Interface, was von außerhalb meiner Klasse kommt immer schön prüfen und umwandeln, bevor es in den Listen landet und/oder verglichen wird. Statt einem Zitat:
Ach ... ich denk nochmal 'nen Tag und dann am Abend gucken, was ich (erstmal) mach. |
AW: Gleiche Interface-Referenzen?
n'Abend.
Es sind bereits alle Parameter niemals als CONST deklatiert. (Das Problem mit den 0-Referenzen kennen wir nun ja bereits) Und dann wird es wohl auf eigene Comparer für die Listen hinauslaufen, welche ausschließlich das interne Objekt vergleichen und die Interfaces bleiben so wie sie sind. :stupid: Schade nur, daß man keine Interface-Methoden als "private" deklarieren kann. In einem anderen Interface würde es zwar verstecken, aber dann gibt es wieder zusätzliche Casts und Referenzen. > muß mir nur überlegen, ob ich diese Methoden öffentlich deklariere, oder ob ich das über Objekt-Referenzen löse. |
AW: Gleiche Interface-Referenzen?
COM schreibt vor, dass ein Objekt für IUnknown immer den selben Zeiger zurückgeben muss (damit die Identität geprüft werden kann).
Und ich gehe mal davon aus, dass Delphi sich mit seinem IInterface auch daran hält (was nicht für Quellen von dritten gelten muss). ps: so in etwa (ungetestet)
Delphi-Quellcode:
function CompareInterface(AInterface1, AInterface2: IInterface): Integer;
var Lhs: IInterface; Rhs: IInterface; begin if Assigned(AInterface1) then if Failed(AInterface1.QueryInterface(IInterface, Lhs)) then Pointer(Lhs) := nil; if Assigned(AInterface2) then if Failed(AInterface2.QueryInterface(IInterface, Rhs)) then Pointer(Rhs) := nil; if PAnsiChar(Lhs) > PAnsiChar(Rhs) then Result := 1 else if PAnsiChar(Lhs) < PAnsiChar(Rhs) then Result := -1 else Result := 0; end; |
AW: Gleiche Interface-Referenzen?
Ja, bei einem Interface-Typ stimmt das,
aber bezüglich der Interface-Vererbung, sieht das wohl nicht ganz so eindeutig aus. :? Es ist garnicht so leicht eine sich selbst referenzierende Baumstrucktur, mit zusätzlichen Verlinkungen, ordentlich hinzubekommen, ohne daß sie sich selbst im Speicher hält und ohne daß abhängige Objekte vorzeitig verschwinden. :stupid: Aber ich glaub langsam hab ich's. (aktuell versuchsweise in einem JSON-DOM implementiert) Nur den Veruch die Speicher-/Referenzverwaltung in generischen Basisklassen zu implementieren und die dann überall zu verwenden, mußte ich leider aufgeben. (mit Makros wäre es bestimmt gegangen, aber die Generics sind einfach nur :kotz:) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:27 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 by Thomas Breitkreuz