AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Interface und Objektreferenz offenbar noch nicht verstanden
Thema durchsuchen
Ansicht
Themen-Optionen

Interface und Objektreferenz offenbar noch nicht verstanden

Ein Thema von Hepdepaddel · begonnen am 18. Sep 2015 · letzter Beitrag vom 30. Sep 2015
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von Hepdepaddel
Hepdepaddel

Registriert seit: 12. Dez 2005
Ort: Bremen
91 Beiträge
 
Delphi 2006 Enterprise
 
#1

AW: Interface und Objektreferenz offenbar noch nicht verstanden

  Alt 18. Sep 2015, 13:18
Erst einmal vielen Dank für die bisherigen Ratschläge! Hier noch die Deklaration von TMySummary

Delphi-Quellcode:
  TMySummary = class(TInterfacedObject, IPlanDataEnumerator)
    public
      CountUnassignedOrderPackages, CountUnassignedOrders: Integer;
      procedure Init;
      procedure HandlePlanDataElement(PD: TPlanData);
  end;
Und hier die Implementierung:

Delphi-Quellcode:
procedure TMySummary.Init;
begin
  Self.CountUnassignedOrderPackages:=0;
  Self.CountUnassignedOrders:=0;
end;


procedure TMySummary.HandlePlanDataElement(PD: TPlanData);
begin
  if PD.IsOrderPackage then begin
    if TOrderPackage(PD).LPOCostType='then Inc(Self.CountUnassignedOrderPackages);
  end;
  if PD.IsOrder then begin
    if TOrder(PD).SAPCostType='then Inc(Self.CountUnassignedOrders);
  end;
end;

Den Ansatz mit zwei Interfaces werde ich nachher gleich mal probieren, wobei ich erstaunt bin, dass man ein ISummary definieren kann und das dann als IPlanEnumerator übergeben kann.
  Mit Zitat antworten Zitat
Benutzerbild von Hepdepaddel
Hepdepaddel

Registriert seit: 12. Dez 2005
Ort: Bremen
91 Beiträge
 
Delphi 2006 Enterprise
 
#2

AW: Interface und Objektreferenz offenbar noch nicht verstanden

  Alt 18. Sep 2015, 13:36
Hi,

der Ansatz mit zwei Interfaces funktioniert leider nicht. Da beschwert sich der Compiler verständlicherweise über inkompatible Typen (ISummary und IPlanDataEnumerator).

Delphi-Quellcode:

TMySummary = class(TInterfacedObject, IPlanDataEnumerator, ISummary)
(...)


procedure Tfrm_Main.UpdateStatusBar;
var
  Summary: ISummary;
begin
  Summary:=TMySummary.Create;
  Summary.Init;
  ProjectData.CallEnumeratorForAllElements(Summary); // <<<<< Hier wird ISummary als IPlanDataEnumerator übergeben
  StatusBar.Panels[1].Text:='Unassigned Order Packages: '+IntToStr(Round(Summary.GetSummaryResult));
end;
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.073 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: Interface und Objektreferenz offenbar noch nicht verstanden

  Alt 18. Sep 2015, 13:51
der Ansatz mit zwei Interfaces funktioniert leider nicht. Da beschwert sich der Compiler verständlicherweise über inkompatible Typen (ISummary und IPlanDataEnumerator).
Hast du ISummary von IPlanDataEnumerator abgeleitet?
  Mit Zitat antworten Zitat
alda

Registriert seit: 24. Mär 2014
Ort: Karlsruhe
93 Beiträge
 
Delphi XE6 Architect
 
#4

AW: Interface und Objektreferenz offenbar noch nicht verstanden

  Alt 18. Sep 2015, 14:08
der Ansatz mit zwei Interfaces funktioniert leider nicht. Da beschwert sich der Compiler verständlicherweise über inkompatible Typen (ISummary und IPlanDataEnumerator).
Eine Klasse kann beliebig viele Interfaces implementieren, das geht schon. Wenn die Interfaces nicht voneinander ableiten und ein impliziter Cast nicht möglich ist, dann musst Du das explizit casten (AS). Allerdings sollte man auch mal schaun ob deine Implementierung insgesamt so Sinn macht.
  Mit Zitat antworten Zitat
Benutzerbild von Hepdepaddel
Hepdepaddel

Registriert seit: 12. Dez 2005
Ort: Bremen
91 Beiträge
 
Delphi 2006 Enterprise
 
#5

AW: Interface und Objektreferenz offenbar noch nicht verstanden

  Alt 18. Sep 2015, 16:06
Ist ja voneinander abgeleitet!
Argh... gucken müsste man können. Freitag, wird Zeit fürs Wochenende.

Das funktioniert jetzt auch so:

Delphi-Quellcode:
procedure Tfrm_Main.UpdateStatusBar;
var
  Summary: IPlanDataEnumerator;
begin
  Summary:=TMySummary.Create;
  TMySummary(Summary).Init;
  ProjectData.CallEnumeratorForAllElements(Summary);
  StatusBar.Panels[1].Text:='Unassigned Order Packages: '+IntToStr(TMySummary(Summary).CountUnassignedOrderPackages);
  StatusBar.Panels[2].Text:='Unassigned Orders: '+IntToStr(TMySummary(Summary).CountUnassignedOrders);
end;
Aber die Variante mit einem spezielleren Enumerator-Interface ist natürlich sauberer. Werde ich nochmal so umsetzen. Die Umsetzung oben gefällt mir nicht wirklich, ist ein wenig so wie eine unverputzte Hauswand.
  Mit Zitat antworten Zitat
Benutzerbild von Hepdepaddel
Hepdepaddel

Registriert seit: 12. Dez 2005
Ort: Bremen
91 Beiträge
 
Delphi 2006 Enterprise
 
#6

AW: Interface und Objektreferenz offenbar noch nicht verstanden

  Alt 18. Sep 2015, 16:07
Und an alle: Besten Dank!
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.073 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: Interface und Objektreferenz offenbar noch nicht verstanden

  Alt 21. Sep 2015, 09:04
Delphi-Quellcode:
procedure Tfrm_Main.UpdateStatusBar;
var
  Summary: IPlanDataEnumerator;
begin
  Summary:=TMySummary.Create;
  TMySummary(Summary).Init;
  ProjectData.CallEnumeratorForAllElements(Summary);
  StatusBar.Panels[1].Text:='Unassigned Order Packages: '+IntToStr(TMySummary(Summary).CountUnassignedOrderPackages);
  StatusBar.Panels[2].Text:='Unassigned Orders: '+IntToStr(TMySummary(Summary).CountUnassignedOrders);
end;
Warum machst du das jetzt so?
Das harte casten auf die Klasse ist suboptimal.
Wenn du möchtest, dass ein klarer(er) Bezug zu IPlanDataEnumerator besteht kannst du es auch so schreiben:
Delphi-Quellcode:
procedure Tfrm_Main.UpdateStatusBar;
var
  Summary: ISummary;
begin
  Summary:=TMySummary.Create;
  Summary.Init;
  ProjectData.CallEnumeratorForAllElements(Summary as IPlanDataEnumerator ); // <<<<< Hier wird ISummary als IPlanDataEnumerator übergeben
  StatusBar.Panels[1].Text:='Unassigned Order Packages: '+IntToStr(Round(Summary.GetSummaryResult));
end;
  Mit Zitat antworten Zitat
Benutzerbild von Hepdepaddel
Hepdepaddel

Registriert seit: 12. Dez 2005
Ort: Bremen
91 Beiträge
 
Delphi 2006 Enterprise
 
#8

AW: Interface und Objektreferenz offenbar noch nicht verstanden

  Alt 24. Sep 2015, 11:24
Warum machst du das jetzt so?
Das harte casten auf die Klasse ist suboptimal.
Entschuldige die späte Antwort - jetzt habe ich den Kopf wieder etwas frei.

Warum mache ich das... gute Frage. Das Problem ist, dass TMySummary eben ein umfangreiches Objekt ist, das mehrere unterschiedliche Interfaces implementieren sollte. Ich bin schon unglücklich, es als IPlanDataEnumerator zu deklarieren. Eigentlich müsste es heißen

Delphi-Quellcode:
var
  Summary: TMySummary;
begin
  Summary:=TMySummary.Create;
  Summary.Init;
  ProjectData.CallEnumeratorForAllElements(Summary as IPlanDataEnumerator);
  StatusBar.Panels[1].Text:='Unassigned Order Packages: '+IntToStr(Summary.CountUnassignedOrderPackages);
  StatusBar.Panels[2].Text:='Unassigned Orders: '+IntToStr(Summary.CountUnassignedOrders);
end;
Ich bin auf das Problem gestoßen, als ich einfach nur "Summary" an die Prozedur übergeben habe - in der Annahme, dass dieses Casting automatisch erfolgt. Dann aber gibt Delphi das Objekt zu früh frei. Mit dem Cast passiert das nicht - aber ich verstehe nicht wirklich warum. Und das fühlt sich ziemlich blöd und unstabil an.

Der Ansatz, Interfaces zu nutzen, die voneinander erben, hilft hier zwar gerade noch, aber löst das Grundproblem nicht. Ich habe noch kein Beispiel gefunden, das den Umgang mit Objekten zeigt, die mehrere unabhängige Interfaces implementieren.

Nehmen wir mal ein anderes Beispiel:

TAutomobil könnte IFarbe, ISteuerung und IMotor implementieren, die nichts miteinander zu tun haben (IFarbe könnte auch von TBauklotz implementiert werden, ISteuerung von TFahrrad, IMotor aber nicht).

Nehmen wir an, wir wollen das Objekt TAutomobil nun umspritzen:

Delphi-Quellcode:
procedure Umspritzen(Gegenstand: IFarbe);
[...]
Umspritzen(TAutomobil)

Dann ergibt es ja keinen Sinn, das Auto mit "var Auto: IFarbe" zu deklarieren. Wir wollen ja das ganze Auto nutzen. Mein erster Ansatz, einfach das Objekt zu übergeben, sah so aus:

Delphi-Quellcode:
var
  Auto: TAutomobil:
[...]
  Auto:=TAutomobil.Create;
  Umspritzen(Auto);
Das führt offenbar dazu, dass ein neues Interface angelegt wird und dann wieder freigegeben wird. Auto scheint nach dem Aufruf von Umspritzen zumindest freigegeben zu sein. Außerdem meine ich beobachtet zu haben, dass die Änderungen am übergegeben Gegenstand nur für das Interface gelten. Man kann innerhalb von Umspritzen dann mit TObject(Gegenstand) arbeiten, dann werden wirklich die Objektattribute geändert. Alles nicht hübsch und wirkt wacklig. Wie es aber offiziell laufen sollte, konnte ich noch nicht sicher herausfinden. Funktioniert eben alles, wirkt aber brüchig.


Um noch ein Beispiel zu nehmen: Ich habe ein Benachrichtigungsobjekt, bei dem sich andere Objekte als Interessent für bestimmte Nachrichten eintragen können, sofern sie IMessageHandler implementieren. Das können Formulare, TInterfacedObject-Nachfahren oder auch sonstige Controls sein. Wenn irgendwo in der Anwendung z.B. ein Budgetwert geändert wird, sorgt das Benachrichtigungsobjekt dafür, dass die Handler-Methode aller eingetragenen Objekte aufgerufen wird. Ich verzichte auf Windows-Messages, weil ich die Ausführung abwarten und die Reihenfolge sehr gezielt steuern will. Wie auch immer: Auch hier habe ich den Fall, dass ich ein Objekt, dass ein bestimmtes Interface implementiert, an eine Funktion übergebe, die genau dieses Interface als Parameter erwartet.

Die perfekte Funktionsdeklaration wäre also:

procedure DoSomethingWithAnObject(Object: "Object which Implements ISomeInterface");
Mal so in Pidgin-Delphi... weil das nicht geht, ist der Parameter vom Typ Interface und es stellt sich die Frage, wie man dann das Objekt korrekt übergibt. "Objekt as ISomeInterface" scheint zu funktionieren, "Objekt" nicht, das führt zur Freigabe des Objekts.
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.352 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: Interface und Objektreferenz offenbar noch nicht verstanden

  Alt 24. Sep 2015, 11:43
Wenn Du mit Interfaces arbeitest solltest Du ab dem Moment nicht mehr mit der Klasse arbeiten.

Wenn Du z.B. eine Autoklasse hast:

TCar = class(TInterfacedObject, IEngine, IColor, IDriver) dann kannst Du später eine Objekt als Interface verwenden:

Delphi-Quellcode:
var Intf: IIinterface;

Intf := TCar.Create;
Dieses kannst Du dann prüfen, ob es auch andere Interfaces implementiert:

Delphi-Quellcode:
var lColor: IColor;
    lEngine: IEngine;
if Supports(Intf, IColor, lColor) then
  lColor.Color := clRed;
if Supports(Intf, IEngine, lEngine) then
  lEngine.Start;
Ab dem Moment kannst bzw. solltest Du nicht mehr mit der Klasse arbeiten. Jedenfalls nicht von außen auf diese zugreifen.


In Deinem Beispiel verstehe ich nicht wirklich, warum Du Summary als Interface ausführen willst. Das könnte doch auch einfach eine Klasse oder ein Record bleiben, der die Zählwerte sammelt.

In Interface bringt Vorteile,
- wenn Du Dich nicht mehr um die Freigabe des Objektes kümmern willst
oder
- wenn Du unterschiedliche (nicht voneinander abgeleitete) Klassen hast, die die gleichen Funktionalitäten implementieren sollen (also an bestimmten Stellen austauschbar sein müssen).


Du kannst ja mal schauen, ob Dir mein Tutorial etwas bringt: http://www.delphipraxis.net/183702-i...-factorys.html
Die Videos vermutlich nicht, aber evtl. die Diskussion dort.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Lemmy

Registriert seit: 8. Jun 2002
Ort: Berglen
2.395 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: Interface und Objektreferenz offenbar noch nicht verstanden

  Alt 24. Sep 2015, 11:48

Nehmen wir mal ein anderes Beispiel:

TAutomobil könnte IFarbe, ISteuerung und IMotor implementieren, die nichts miteinander zu tun haben (IFarbe könnte auch von TBauklotz implementiert werden, ISteuerung von TFahrrad, IMotor aber nicht).
nein sicher nicht. TAutomobil implementiert NICHT IMotor, denn ein Auto IST kein Motor, sondern ein Auto HAT einen Motor, also wäre richtig:

Delphi-Quellcode:
type
  TAutomobil = class(xyz)
  private
    FMotor: IMotor
....
Und das macht einen deutlichen Unterschied. Dito mit Steuerung und Farbe (wobei Farbe wieder eine Eigenschaft von Karosserie wäre, weil die Inneneinrichtung ja auch ne Farbe (mehrere) hat).

Prüf mal dein TSummary - ich vermute Du hast hier ein vergleichbares Problem: EIn Superobjekt, das zu viele Zuständigkeiten hat und ggf. anders aufgeteilt werden sollte...
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 18:57 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