Autor Beitrag
Luuuz
Hält's aus hier
Beiträge: 4



BeitragVerfasst: So 09.05.10 15:08 
Hallo,

ich implementiere gerade eine Observer Pattern. Hierzu muss ich mir sämtliche Observer in einer dynamischen Liste von TObjects merken.
Später will ich auf diesen Objekten die Methode "Notify" aufrufen. Sprich ich muss diese Objekte nach IObserver casten. (IObserver enthält die Vereinbarung über die Notify Methode).

Normalerweise müsste ich folgendes schreiben:
ausblenden Delphi-Quelltext
1:
IObserver(MyList.Items[i]).Notify();					

oder
ausblenden Delphi-Quelltext
1:
(MyList.Items[i] as IObject).Notify();					

Diese Ansätze funktionieren leider nicht. Die Variante mit "as" könnte ich nur einsetzen, wenn TObject immer das Interface IObserver implementieren würde.

Gibt es hierfür einen Trick, oder ist dieser Anwendungsfall wirklich nicht vorgesehen ?!?!

Besten Dank im Voraus!

Tobias


Moderiert von user profile iconNarses: Topic aus Sonstiges (Delphi) verschoben am Mo 10.05.2010 um 00:28
Moderiert von user profile iconNarses: B- durch Delphi-Tags ersetzt
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 09.05.10 16:54 
Sollte das nicht mit TInterfaceList besser gehen?

Und davon unabhängig: Wenn du auf die Klasse castest, die das Interface implementiert, kannst du dann nicht auch auf dein Interface casten?

Und warum eigentlich TObject? Ist da nicht TInterfacedObject passender?
Luuuz Threadstarter
Hält's aus hier
Beiträge: 4



BeitragVerfasst: So 09.05.10 17:22 
Hallo jaenicke,
vielen Dank für die Antwort.

Ich verwende die TObjectList, deshalb habe ich aus Ausgangsdatentyp TObject.
Alle Elemente dieser Liste implementieren das Interface IObserver und sind bereits initialisierte GUI Controls.

In der TInterfaceList kann ich meines Wissens nach nur Interfaces speichern. Ich benötige aber eine Liste in der dich die "fertigen" Objekte speichern kann.

Wenn ich anstatt der TObjectList ein statisches IObserver Array verwende funktioniert es einwandfrei.
Eine dynamische Liste würde sich für den Anwendungsfall aber eher anbieten...

Gruß
Tobias
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 09.05.10 18:27 
Wie ich schon sagte: Mit Cast auf einen gemeinsamen Vorfahren, der das Interface implementiert, geht es doch.

// EDIT:
Um es deutlich zu machen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
  ITest = interface
    procedure Test;
  end;

  TTest = class(TInterfacedObject, ITest)
  public
    procedure Test;
  end;

// ...

var
  a: TObjectList;
begin
  ITest(TTest(a.Items[0])).Test;
Geht ;-)
baka0815
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 489
Erhaltene Danke: 14

Win 10, Win 8, Debian GNU/Linux
Delphi 10.1 Berlin, Java, C#
BeitragVerfasst: Fr 25.06.10 16:05 
user profile iconjaenicke: Das macht aber überhaupt keinen Sinn.

Wenn ich erst auf einen gemeinsamen Vorfahren casten muss, der kein Interface ist, kann ich statt dem Interface auch eine abstrakte Klasse verwenden - durch das Interface hätte ich nichts gewonnen.

Tatsächlich muss man aber scheinbar, wie du gesagt hast, eine TInterfaceList verwenden. Das funktioniert dann problemlos - auch mit den "fertigen" Objekten:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
type
  IMeinInterface = interface
    procedure Test;
  end;

type
  TMeineKlasse = class(TInterfacedObject, IMeinInterface)
    procedure Test;
end;

procedure Test(Intf: IMeinInterface);
var
  Liste: TInterfaceList;
  I: Integer;
begin
  Liste := TInterfaceList.Create;
  try
    Liste.Add(Intf);
    Intf.Test;
    for I := 0 to Liste.Count - 1 do
      IMeinInterface(Liste.Items[I]).Test;
    Liste.Remove(Intf);
  finally
    Liste.Free;
  end;
end;

procedure Test2;
begin
  Test(TMeineKlasse.Create);
end;
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Fr 25.06.10 17:27 
Du kannst ein "nacktes" Objekt nicht direkt in ein Interface casten, es sei denn du verwendest GUIDs oder machst den Umweg über die konkrete Klasse.

Der Grund dafür ist, dass der Interface-Pointer <> Objekt-Pointer ist und der Offset auf die Adresse auf die Functiontable unbekannt ist. Wenn du GUIDs verwendest, kannst du über QueryInterface bzw. über Supports() auf Interfaces casten bzw. herausfinden, ob ein Interface implementiert wird.

Am Rande bemerkt: Das Observer-Pattern wird eher im Bereich Java verwendet. In Delphi gibt's Events, wobei man die zwei Dinge nicht gleichsetzen kann.