AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Interface referenzen auf gleichheit prüfen?
Thema durchsuchen
Ansicht
Themen-Optionen

Interface referenzen auf gleichheit prüfen?

Ein Thema von maximov · begonnen am 11. Okt 2004 · letzter Beitrag vom 14. Okt 2004
Antwort Antwort
Seite 1 von 3  1 23      
Benutzerbild von maximov
maximov

Registriert seit: 2. Okt 2003
Ort: Hamburg
548 Beiträge
 
Delphi 2005 Professional
 
#1

Interface referenzen auf gleichheit prüfen?

  Alt 11. Okt 2004, 12:58
Moin,

ich bin gezwungen (von mir selbst) diverse interface-referenzen (COM) zu vergleichen, was sich als schwer heraustellt, da verschiednene ITypen verschiedene binäre-adressen auf ein und das selbe objekt haben.

Stark vereinfachter versuchsaufbau:

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type

  // test typen

  iA = interface
    procedure A;
  end;

  TA= class(TInterfacedObject,iA)
  public
    procedure A;
  end;

  iB = interface(iA)
    procedure B;
  end;

  TAB = class(TA,iB)
  public
    procedure B;
  end;

  {*********************************************}

  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    Button2: TButton;
    Button3: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    fA:iA;
    fB:iB;
    fRef:TAB;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FRef := TAB.Create; // object erzeugen, das einzige
  fB := fRef; // ref 1
  fA := fRef; // ref 2
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  // hier sieht man, dass alle drei referenzen verschiedene addressen haben...
   memo1.Lines.Add(format('ref = %p | a = %p | b = %p',[pointer(fRef),pointer(fA),pointer(fB)]));
  // zB so: ref = 008D24E4 | a = 008D24F0 | b = 008D24F4
end;

{ TA }

procedure TA.A;
begin
  ShowMessage('A');
end;

{ TAB }

procedure TAB.B;
begin
  ShowMessage('B');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  fA.A;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  FB.B;
  FB.A;
end;

end.
das ergebnis wäre zB:
Code:
ref = 008D24E4 | a = 008D24F0 | b = 008D24F4
und ich sehe auch ein, dass das intern für die COM implementierung irgendwie so sein muss...

...ABER wie vergleicht man diese referenzen so, dass TRUE bei rumm kommt?

Danke, in erwartung
mâxîmôv.

{KDT}
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#2

Re: Interface referenzen auf gleichheit prüfen?

  Alt 11. Okt 2004, 14:00
Du könntest ein weiteres Interface einführen:
Delphi-Quellcode:
ICompareRef = interface
    function GetCookie:Integer;
  end;
Alle Klassen sollten dann dieses Interface implementieren:
Delphi-Quellcode:
  TA= class(TInterfacedObject,iA, ICompareRef)
  private
     FCookie : Integer;
  protected
    function GetCookie:Integer;
  public
    constructor Create;
    procedure A;
    
  end;

function TA.GetCookie:Integer;
begin
   Result := FCookie;
end;

constructor TA.Create;
begin
   // GlobalCookieCounter ist eine globale Variable
   // sie beim Erzeugen eines Objekte um 1 hochgezählt
   FCookie := InterlockedIncrement(GlobalCookieCounter);
end;
Und so wird's benutzt
Delphi-Quellcode:
   if (fA as ICompareRef).GetCookie=(fB as ICompareRef).GetCookie then
      ShowMessage('die Dinger sind gleich');
Andreas
  Mit Zitat antworten Zitat
Benutzerbild von maximov
maximov

Registriert seit: 2. Okt 2003
Ort: Hamburg
548 Beiträge
 
Delphi 2005 Professional
 
#3

Re: Interface referenzen auf gleichheit prüfen?

  Alt 11. Okt 2004, 14:16
Ok, du meinst ich soll allen objekten eine eindeutoge ID geben. Das wäre IMO schon fast ein overkill, da ein objekt ja eigentlich eindeutig ist... Dann könnte ich eigentlich an stelle der ID auch die Object-referenz zurück liefern, denn wenn ich erstmal in dem TObject bin, dann ist self natürlich immer gleich.


Ich dachte eigentlich eher an eine native delphi funktionen oder so? Sowas wie
function isSameIntfObject(const i1,i2:IInterface):boolean; Das ist bestimmt möglich!?


//edit: equal <> same
mâxîmôv.

{KDT}
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#4

Re: Interface referenzen auf gleichheit prüfen?

  Alt 11. Okt 2004, 14:32
Ich vermute mal das du in deinem Konzept einen Denkfehler hast.
Verschiedene Objecte können mehrere verschiedene Interfaces implementieren. Zb.

Delphi-Quellcode:
  TClass_AB = class(TInterfacedObject, IInterface_A, IInterface_B)
  end;

  TClass_AC = class(TInterfacedObject, IInterface_A, IInterface_C)
  end;

  TClass_BC = class(TInterfacedObject, IInterface_B, IInterface_C)
  end;
Nun hast du mehrere allozierte Interfaces obiger Typen und möchtest wissen ob dieses das Interface A verwenden. Das geht indem man GUIDs benutzt, denoch könnten dann "gleiche" Objecte die das IInterface_A implementieren der Klassen TClass_AB und TClass_AC angehören, d.h. der Implementor des Interfaces ist denoch nicht gleich.

Willst du aber nun überprüfen ob die Implementierenden Klassen identisch sind dann musst du selber eine Schnittstelle dafür programmieren. Dazu könntest du das Delphi Klassen Konzept benutzen, etwa so:

Delphi-Quellcode:
type
  IImplementor = interface
    ['0896943-093893-498574'] // <- deine GUID hier eintragen !! in IDE [STRG+ALT+G]
    function Object: TObject;
  end;

  TClass_AB = class(TInterfacedObject, IImplementor, IInterface_A, IInterface_B)
  end;
  
  TClass_AC = class(TInteefacedObject, IImplementor, IInterfase_A, IInterface_C)
  end;

 
function TClass_AB.Object: TObject;
begin
// Result := Self; // <- da EAX schon Self enthält, und EAX das Result ist reicht eine leere Funktion hier aus !!
end;

function Compare(const A,B: IInterface): Boolean;
var
  AI,BI: IImpelementor;
begin
  Result := (A.QueryInterface(AI, IImplementor) = H_OK) and
            (B.QueryInterface(BI, IImplementor) = H_OK) and
            (AI.Object.ClassType = BI.Object.ClassType);
end;
Gruß Hagen
  Mit Zitat antworten Zitat
choose

Registriert seit: 2. Nov 2003
Ort: Bei Kiel, SH
729 Beiträge
 
Delphi 2006 Architect
 
#5

Re: Interface referenzen auf gleichheit prüfen?

  Alt 11. Okt 2004, 15:43
Hallo Maximov,

wie Hagen bereits dargestellt hat, handelt es sich bei Schnittstellen (Interfaces) um unterschiedliche "Sichten" auf ein und dasselbe Objekt. Weil die Identität eines Objekts jedoch ein Wesensmerkmal darstellt, scheint es tatsächlich überaschend, dass der von Dir diskutierte Code bei einen Vergleich der Art
Delphi-Quellcode:
myObj := TMyClass.Create;
myRefToInterfaceA := myObj;
myRefToInterfaceBA := myObj;
Result := Pointer(myRefToInterfaceA) = Pointer(myRefToInterfaceB);
den Wert False zurückgibt.

Tatsächlich ist dies lediglich spezifisch für Wahl der Implementierung von Interfaces im COM-Umfeld, bei der jede Klasse für jedes implementierte Interface seine eigene "Methodentabelle" bereitstellt, auf die (indirekt) durch die Referenz auf ein Interface verwiesen wird.
Obgleich es möglich ist, Schnittstellen voneinander erben zu lassen und Zuweisungen der Art
Delphi-Quellcode:
type
  IMyInterface = interface
  ['{A GUID}']
  end;

  IMyInterfaceDescendant = interface(IMyInterface)
  ['{Another GUID}']
  end;

  TMyClass = class(TInterfacedObject, IMyInterfaceDescendant)
  end;

var
  myObject: TMyClass;
  myRefToInterface: IMyInterface;
  myRefToInterfaceDescendant: IMyInterfaceDescendant;
begin
  myObject := TMyClass.Create;
  myRefToInterfaceDescendant := myObject;
  myRefToInterface := myRefToInterfaceDescendant;
durchzuführen, obwohl die Klasse TMyClass aus dem Beispiel das Interface IMyInterface selbst nicht implementiert, ist eine Zuweisung der Art
myRefToInterface := myObject nicht zulässig wie auch der Cast
myObject as IMyInterface zu einer Exception führt: Das Interface IMyInterface wird von TMyClass nicht implementiert, es kann keine Referenz auf die "Methodentabelle" zurückgegeben werden.


Was Du also machen kannst, wenn Du ohne "Identitätsinterface", wie Hagen es vorschlägt, an die Identität der Objekte zweier unterschiedlicher Interfaces herankommen möchtest, ist der Cast auf auf ein gemeinsames Interface, z.B. IInterface, und der anschließende Vergleich der Art
Result := (myRefToAnInterface as IInterface) = (myRefToAnotherInterface as IInterface) Achtung: Wie oben beschrieben sind Zuweisungen zu Vorfahren-Interfaces gültig, also im Speziellen Zuweisungen zum Wurzelinterface IInterface. Ein Vergleich nach
Delphi-Quellcode:
var
  myHelper1: IInterface;
  myHelper2: IInterface;
begin
  myHelper1 := ARefToAnInterface;
  myHelper2 := ARefToAnnotherInterface;
  Result := myHelper1 = myHelper2;
kann demnach zu fehlern führen!
gruß, choose
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#6

Re: Interface referenzen auf gleichheit prüfen?

  Alt 11. Okt 2004, 15:59
@Choose:

der Vergleich

Result := (myRefToAnInterface as IInterface) = (myRefToAnotherInterface as IInterface) ist nicht zwangsläufig durchführbar.
Angenommen:

Delphi-Quellcode:
  
  Result := (myRefToAnInterface as IInterface_A) = (myRefToAnotherInterface as IInterface_A)

und

type
  TClassBase = class(TInterfacedObject, IInterface_A)
  end;

  TClassA = class(TClassBase, IInterface_B)
  end;
  
  TClassB = class(TClassBase, IInterface_C)
  end;
dann würde obiger Vergleich TRUE liefern auch wenn man ein Object vom Typ TClassA mit TClassB vergleicht, denn beide basieren in ihrer Impelementierung von IInterface_A auf TClassBase. Man hätte also nur die Information das beide Objecte die IInterface_A Schnittstelle auf gleicher Basis impelemntiert haben. Da aber TClass_B zB. die Methoden von IInterface_A intern überschrieben haben können, wären auch untrschiedliche Implementierungen vom IINterface_A möglich. Der Vergleich würde als TRUE zurückliefern obwohl es sich a.) um unterschiedliche Klassen handelt und b.) deren Implementierungen unterschiedlich wären.

Somit wäre das Result TRUE logisch gesehen eine Falschaussage.

Gruß Hagen
  Mit Zitat antworten Zitat
choose

Registriert seit: 2. Nov 2003
Ort: Bei Kiel, SH
729 Beiträge
 
Delphi 2006 Architect
 
#7

Re: Interface referenzen auf gleichheit prüfen?

  Alt 11. Okt 2004, 16:25
Hallo Hagen,

nach Deinem Ansatz von oben und der daraus abgeleiteten Implementierung:
Delphi-Quellcode:
type
  IMyBaseInterface = interface
  ['{3F3E45E4-3FD4-4326-A2FE-637339B4E8A9}']
  end;

  IMyInterfaceA = interface
  end;

  IMyInterfaceB = interface
  end;


  TMyBaseClass = class(TInterfacedObject, IMyBaseInterface)
  end;

  TMyClassA = class(TMyBaseClass, IMyInterfaceA)
  end;

  TMyClassB = class(TMyBaseClass, IMyInterfaceB)
  end;

var
  myRefToInterfaceA : IMyInterfaceA;
  myRefToInterfaceB : IMyInterfaceB;

  myCompareRefA : IMyBaseInterface;
  myCompareRefB : IMyBaseInterface;
begin
  myRefToInterfaceA := TMyClassA.Create;
  myRefToInterfaceB := TMyClassB.Create;

  myCompareRefA := myRefToInterfaceA as IMyBaseInterface;
  myCompareRefB := myRefToInterfaceB as IMyBaseInterface;
ergibt der Vergleich
Result := myCompareRefA = myCompareRefB entgegen Deiner Aussage immer False, weil die beiden erzeugten Exemplare (unabhängig davon, ob sie Exemplare unterschiedlicher Klassen, einen gemeinsamen Vorfahren, der besagtes Interface IMyBaseInterface implementiert, besitzen oder derselben Klasse angehören), weil sie voneinandert verschiedene Identitäten haben.

Innerhalb einer Schnittstellenreferenz ist (indirekt) die "Methodentabelle" der Klasse zur Realisierung des Interfaces und die Identität des Objekts codiert. Wäre dies nicht so und zeigte myCompareRefA für jedes Exemplar der Klasse TMyClassA auf dieselbe Adresse, wäre die Verwendung der Pseudovariablen Self innerhalb von so referenzierten Methoden nicht möglich...

Ich hoffe, dass ich Dich richig verstanden und nicht am Thema vorbeigeschrieben habe
gruß, choose
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#8

Re: Interface referenzen auf gleichheit prüfen?

  Alt 11. Okt 2004, 18:10
Nene, ich meinte das die gemeinsamme Vorfahrklasse das zu vergleichende Interface implementieren. Also:

Delphi-Quellcode:
  TClassBase = class(..., IInterface_A)

  TClass_B = class(TClassBase, IInterface_B)
  TClass_C = class(TClassBase, IInterface_C)
Beide Klassen, B und C impelementieren auf Grund von Vererbung auch IInterface_A.
Ein Vergleich von Objecten der Klassen B und C auf das Interface IInterface_A würde demnach TRUE ergeben.

Ich müsste das aber auch noch erst praktisch überprüfen. Mein Grundgedanke lief aber daraus hinaus das nur die Klasse TClassBase in ihrer RTTI die VMT für IInterface_A im Codesegment speichert. Die Klassen A und B wiederum erben diese VMT indirekt durch die Verebung von TClassBase.

Aber egal, wenn man meinen obigen Vorschlag benutzt so ist man definitiv auf der sauberen Seite, denn das muss immer korrekt funktionieren da wir eben nicht auf interne und undokumentirte Implementierungsdetails des Delphi Compilers und dessen RTTI/VMTs aufsetzen.

Generell muß man eben wissen das ein Interface nur eine reine Deklaration "wie was" sein sollte, aber eben nicht "wo was" tatsächlich ist, darstellt.
Somit kann man bei einer Variable nur überprüfen ob sie ein Interface X unterstützt aber nicht wie, wo und wer sie tatsächlich implementiert. Somit kann man auf Grund des Interface Konzeptes nicht ermitteln ob die Implemntation == Delphi Klasse/Object identische Typen sind. Mit meinem Vorschlag wird aber genau das ermöglicht, ohne das man sich auf undokumentierte Funktinalitäten eines Compilers verlassen muß.


Gruß Hagen
  Mit Zitat antworten Zitat
choose

Registriert seit: 2. Nov 2003
Ort: Bei Kiel, SH
729 Beiträge
 
Delphi 2006 Architect
 
#9

Re: Interface referenzen auf gleichheit prüfen?

  Alt 11. Okt 2004, 18:23
Hey Hagen,

ich glaube, dass wir aneinander vorbeischreiben, vielleicht könnte Maximov an dieser Stelle seine Anfrage richtigstellen. Wenn ich ihn richtig verstanden habe, möchte er feststellen, ob es sich bei zwei Objekten, die sich hinter Interfacereferenzen unterschiedlichen Typs verbergen, um ein und dasselbe Exemplar (und damit implizit derselben Klasse, weil Delphi keine Mehrfahvererbung unterstützt) handelt.
Du, Hagen, scheinst jedoch zeigen zu wollen, ob die Klassen zweier Exemplare hinter zweier Interfacereferenzen und nur die Klassen identisch sind, ohne auf die Identität der Exemplare einzugehen.

Ohne Interfaces also
Delphi-Quellcode:
//prüfen, ob Objekte identisch
Result := AnObject = AnotherObject;
bzw.
Delphi-Quellcode:
//prüfen, ob Klassen identisch
Result := AnObject.ClassType = AnotherObject.ClassType;
Bitte korrigiere micht jemand, wenn ich falsch liege.
gruß, choose
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#10

Re: Interface referenzen auf gleichheit prüfen?

  Alt 11. Okt 2004, 18:50
Ja und, schau dir obigen Code mal genaur an

Delphi-Quellcode:
function Compare(const A,B: IInterface): Boolean;
var
  AI,BI: IImpelementor;
begin
  Result := (A.QueryInterface(AI, IImplementor) = H_OK) and
            (B.QueryInterface(BI, IImplementor) = H_OK) and
            (AI.Object.ClassType = BI.Object.ClassType);
end;
vergleicht die Klassen, und daraus wird

Delphi-Quellcode:
function Compare(const A,B: IInterface): Boolean;
var
  AI,BI: IImpelementor;
begin
  Result := (A.QueryInterface(AI, IImplementor) = H_OK) and
            (B.QueryInterface(BI, IImplementor) = H_OK) and
            (AI.Object = BI.Object);
end;
um die zu implementierenden Objecte zu vergleichen. Bei TRUE wird das Interface in A und B durch das selbe Object implementiert, ergo A und B stellen das selbe Object dar, auch WENN eben Pointer(A) == Pointer(B) FALSE ist. Ich hätte gedacht das nach dem Studium meines obigen Postings das eigentlich trivial ist und jeder das so ableiten kann.

Da wir das absichtlich so konstruiert haben muß das funktionioren, es basiert also nicht auf undokumentierten Annahmen wie Delphis Compiler intern was macht.

Gruß Hagen
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:37 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz