Arbeiten mit Interfaces, wie macht man es korrect ? [Gelöst]

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Arbeiten mit Interfaces, wie macht man es korrect ? [Gelöst]

Beitrag von corpsman »

Hallo Zusammen,

Ich will grad mal ein klein wenig zum Thema Interfaces "lernen" und habe mir dazu die angehänge Testapp gebastelt.

Im Anhang habe ich eine kleine Demo angehängt, die leider nicht "funktioniert", weil ich noch nicht genug gelernt habe :/

Worum es geht:

Ich habe 3 Classen TVehicle, TCar und TPlane die den Namen entsprechend "abgeleitet" sind.

Code: Alles auswählen

Unit uInterface_Example;

{$MODE ObjFPC}{$H+}

Interface

Uses
  Classes, SysUtils;

Type

  IInterface = Interface
    Function CanFly: Boolean; virtual; abstract;
  End;

  { TVehicle }

  TVehicle = Class(TInterfacedObject)
  private
  public
    Name: String;
    Position: TPoint;
    Constructor Create(); virtual;
  End;

  TCar = Class(TVehicle)
  private
  public
  End;

  TPlane = Class(TVehicle)
  private
  public
  End;

  { TInterfacedVehicle }

  TInterfacedVehicle = Class(TVehicle, IInterface)
    Function CanFly: Boolean; virtual;
  End;

  { TInterfacedCar }

  TInterfacedCar = Class(TCar, IInterface)
  public
    Function CanFly: Boolean; virtual;
  End;

  { TInterfacedPlane }

  TInterfacedPlane = Class(TPlane, IInterface)
  public
    Function CanFly: Boolean; virtual;
  End;

Implementation

{ TVehicle }

Constructor TVehicle.Create();
Begin
  name := ClassName;
End;

{ TInterfacedVehicle }

Function TInterfacedVehicle.CanFly: Boolean;
Begin
  result := false;
  Raise exception.create(classname + '.CanFly not implemented.');
End;

{ TInterfacedCar }

Function TInterfacedCar.CanFly: Boolean;
Begin
  result := false;
End;

{ TInterfacedPlane }

Function TInterfacedPlane.CanFly: Boolean;
Begin
  result := true;
End;

End.
Nun möchte ich im Prinzip an TCar und TPlane eine weitere Function anfügen ohne TVehicle ändern zu müssen, da dachte ich mir genau das machen doch Interfaces..

Im Beispiel habe ich dazu TInterfacedCar und TInterfacedPlane erzeugt.

Mein Problem ist nun, dass ich alle meine Vehicles in einer Variable sammeln will dazu habe ich

Code: Alles auswählen

var
  MyVehicles: Array Of TInterfacedVehicle;


Wenn ich nun aber Instancen erstellen will meckert der Compiler:

Code: Alles auswählen

Procedure TForm1.Button1Click(Sender: TObject);
Begin
  // Buy Car
  setlength(MyVehicles, high(MyVehicles) + 2);
  MyVehicles[high(MyVehicles)] := TInterfacedCar.Create(); // -- Das hier geht nicht
  UpdateMyVehicles;
End;
Klar eine Lösung wäre ich füge das IInterface an TVehicle zu, dann könnte ich mir auch TInterfacedVehicle sparen, aber wenn ich das mache und es gibt noch weitere KindKlassen von TVehicle die sich nicht ändern sollen würde der Compiler diese nicht mehr bauen.

Wie macht man das also Richtig ?
Dateianhänge
Demo.zip
(2.75 KiB) 92-mal heruntergeladen
Zuletzt geändert von corpsman am Do 15. Mai 2025, 15:47, insgesamt 1-mal geändert.
--
Just try it

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2822
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Arbeiten mit Interfaces, wie macht man es korrect ?

Beitrag von m.fuchs »

Erste Frage: Benötigst du die Referenzzählung? Wenn nicht - das ist dann der Fall wenn du ein Interface wie ein klassisches Interface benutzen willst - kannst du mal die Compilerdirektive

Code: Alles auswählen

{$INTERFACES CORBA}
hinzufügen. Dann muss TVehicle auch nicht von TInterfacedObject ableiten.

Dann störe ich mich ein bisschen an dem Namen IInterface, der sagt nämlich nicht aus was das Ding tut - das ist fürs Verständnis schlecht und deswegen verstehe ich deine Absichten vielleicht falsch.

Ich glaube dass dein Klassen- / Interface-Struktur nicht das ist, was du möchtest. TInterfacedCar steht in keiner Beziehung zu TInterfacedVehicle, also kann es logischerweise nicht an ein Array Of TInterfacedVehicle übergeben werden. Die Frage ist ja: was möchtest du erreichen?
Hilft dir eventuell das hier:

Code: Alles auswählen

var
  MyVehicles: Array Of IInterface;             
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Arbeiten mit Interfaces, wie macht man es korrect ?

Beitrag von corpsman »

Servus Michael,

Du hast Recht IInterface wurde "sinnvoll" umbenannt, und Cobra gesetzt.

Code: Alles auswählen

Unit uInterface_Example;

{$MODE ObjFPC}{$H+}

{$INTERFACES CORBA}

Interface

Uses
  Classes, SysUtils;

Type

  ICanFlyIInterface = Interface
    Function CanFly: Boolean; virtual; abstract;
  End;
Das Thema was mich aber tatsächlich zum erstellen eds Posts gebracht hat, haben wir noch offen ;)

Ich hab

Code: Alles auswählen

  TInterfacedCar = Class(TCar, ICanFlyIInterface)
  
Meine Erwartungshaltung war, dass das ein TCar ist (der ja von TVehicle Abgeleitet ist) + das ICanFlyIInterface

Wenn ich mache

Code: Alles auswählen

   MyVehicles: Array Of ICanFlyIInterface;
Wie du es vorschlägst, dann kann ich in UpdateMyVehicles nicht mehr auf ".name" zugreifen, weil das Interaface ja den Namen gar nicht hat.

Code: Alles auswählen

Procedure TForm1.UpdateMyVehicles;
Var
  i: Integer;
Begin
  ListBox1.items.BeginUpdate;
  ListBox1.Clear;
  For i := 0 To high(MyVehicles) Do Begin
    If MyVehicles[i].canFly Then Begin
      ListBox1.Items.add(TVehicle(MyVehicles[i]).name + ' flyable'); // Hier knallts bei der Ausführung obwohl TVehicle es ja kann ?
    End
    Else Begin
      ListBox1.Items.add(TVehicle(MyVehicles[i]).name + ' drivable');
    End;
  End;
  ListBox1.items.EndUpdate;
End;  
Den Namen ins Interface auf zu nehmen geht leider nicht.

Code: Alles auswählen

  ICanFlyIInterface = Interface
    Name:String; // Das mag der Compiler nicht
    Function CanFly: Boolean; virtual; abstract;
  End; 
Ich hoffe es ist ein bisschen "Klarer" geworden, wenn nicht freue ich mich über deine Fragen, dann schärfe ich nach ;)

Wenn ich so über all das nachdenke wäre wahrscheinlich ein TypeHelper besser, bzw versuche ich gerade das Interface zu einem Typehelfer zu "Misbrauchen" ?
--
Just try it

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2822
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Arbeiten mit Interfaces, wie macht man es korrect ?

Beitrag von m.fuchs »

Ich bin mir immer noch nicht sicher, was du eigentlich bezwecken möchtest. Ich lese die Klassennamen und das Interface aber ich erkenne "die Geschichte dahinter" nicht so richtig.

Nehmen wir mal an es wir haben unsere Vehikel und möchten bestimmen ob eines davon fliegen kann oder nicht.

Dann würde ich entweder CanFly in die Basisklasse TVehicle setzen oder mir eben ein Interface IFlyingVehicle bauen, welches ich in den Klassen in die Ableitung mit aufnehme, die fliegen können müssen. Allerdings würde ich dann auf CanFly verzichten, denn dies ergibt sich schon aus der Tatsache dass von IFlyingVehicle abgeleitet wird. Stattdessen bräuchte es eher eine Method Fly, die den eigentlichen Flug durchführt.

Das kann man aber auch problemlos mit einer Klassenhierarchie wie folgender aufbauen:
klassen.png
klassen.png (13.6 KiB) 2051 mal betrachtet
Ich bin mir also unsicher, ob an dieser Stelle das Interface das passende ist.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Arbeiten mit Interfaces, wie macht man es korrect ?

Beitrag von corpsman »

*g*
Aus den Schwierigkeiten dir das zu erklären und meinen Überlegungen, hatte ich ja ebenfalls bereits bemerkt, dass wahrscheinlich ein Typehelper hier der passendere ist.

Für das Beispiel und mein "realproblem" ist das eine Elegante Lösung.

Aber mein Versuch etwas zu Interfaces zu lernen und damit in Zukunft Situationen zu erkennen, wo diese Sinn machen ist damit dann leider gescheitert.

Ich denke mit den Interfaces ist es wie mit den TFrames, ich brauche diese recht selten, aber wenn dann bin ich echt froh zu wissen dass es sie gibt und wie man sie nutzt. Und genau dieses "wissen was man mit Interfaces machen kann und wo sie Sinn machen" fehlt mir aktuell noch :/
--
Just try it

Benutzeravatar
kupferstecher
Beiträge: 434
Registriert: Do 17. Nov 2016, 11:52

Re: Arbeiten mit Interfaces, wie macht man es korrect ?

Beitrag von kupferstecher »

So wie es m.fuchs gemeint hat, würde ich es auch machen.

Also:

Code: Alles auswählen

INTERFACE
var
  MyVehicles: Array Of TVehicle;

IMPLEMENTATION

  if MyVehicles[i] is IFlyingVehicle
  then IFlyingVehicle(MyVehicles[i]).StartFlying;

Man könnte es in dem Beispiel zwar wohl auch direkt über eine abgeleitete Klasse abbilden. Das Interface benötigt man aber dann, wenn es keine einfache Baumstruktur mehr gibt, z.b. wenn man noch ein WheeledVehicle einführt.

Auto: WheeledVehicle
Passagierjet: FlyingVehicle, WheeledVehicle
Wasserflugzeug: FlyingVehicle

Oder auch dann, wenn man an die Elternklasse nicht mehr ran kommt, z.B. wenn man Formulare im FormEditor erstellt und denen noch eine gemeinsame Methode verpassen möchte, also einen speziellen Typ Formular daraus machen.

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1648
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Arbeiten mit Interfaces, wie macht man es korrect ?

Beitrag von fliegermichl »

Ich hab im englischen Forum einen netten Beitrag zu dem Thema gefunden.

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Arbeiten mit Interfaces, wie macht man es korrect ?

Beitrag von corpsman »

Ok, das mit den Typehelpern hat nicht geklappt.
Dann versuche ich noch mal zu beschreiben was ich eigentlich machen will..

Ich hab eine Fremd "lib" in der Klassen definiert sind die sind in der unit uDoNotTouchMe.pas und die sieht so aus:

Code: Alles auswählen

Unit uDoNotTouchMe;

{$MODE ObjFPC}{$H+}

Interface

Uses
  Classes, SysUtils;

Type

  { TVehicle }

  TVehicle = Class
  private
  public
    Name: String;
    Constructor Create(); virtual;
  End;

  TCar = Class(TVehicle)
  private
  public
  End;

  TPlane = Class(TVehicle)
  private
  public
  End;

Implementation

{ TVehicle }

Constructor TVehicle.Create();
Begin
  name := ClassName;
End;

End.
Nun will ich allen dieser Klassen eine weitere Methode geben.

Code: Alles auswählen

 Function NewFeature: String; 
Da ich aber die DoNotTouch nicht ändern Kann / will erstelle ich eine neue unit uExtended_dont_touch:

Code: Alles auswählen

Unit uExtended_Dont_Touch;

{$MODE ObjFPC}{$H+}

Interface

Uses
  Classes, SysUtils, uDoNotTouchMe;

Type

  { TVehicleHelper }

  TVehicleHelper = Class Helper For TVehicle
    Function NewFeature: String;
  End;

  { TCarHelper }

  TCarHelper = Class Helper For TCar
    Function NewFeature: String;
  End;

  { TPlaneHelper }

  TPlaneHelper = Class Helper For TCar
    Function NewFeature: String;
  End;

Implementation

Uses Dialogs;

{ TVehicleHelper }

Function TVehicleHelper.NewFeature: String;
Begin
  result := 'TVehicleHelper Class: ' + ClassName + ' Name:' + Name;
End;

{ TCarHelper }

Function TCarHelper.NewFeature: String;
Begin
  result := 'TCarHelper Class: ' + ClassName + ' Name:' + Name;
End;

{ TPlaneHelper }

Function TPlaneHelper.NewFeature: String;
Begin
  result := 'PlaneHelper Class: ' + ClassName + ' Name:' + Name;
End;

End.

Durch die Type helper kann ich in meiner Main Form den polymorphismus nutzen:

Code: Alles auswählen

var
    MyVehicles: Array Of TVehicle; 
    
    Procedure TForm1.Button1Click(Sender: TObject);
Begin
  // Buy Car
  setlength(MyVehicles, high(MyVehicles) + 2);
  MyVehicles[high(MyVehicles)] := TCar.Create();
  UpdateMyVehicles;
End;

Procedure TForm1.Button2Click(Sender: TObject);
Begin
  // Buy Plane
  setlength(MyVehicles, high(MyVehicles) + 2);
  MyVehicles[high(MyVehicles)] := TPlane.Create();
  UpdateMyVehicles;
End;   
Wenn ich nun aber meine Fahrzeuge ausgebe, dann sieht man in der Listbox: dass es nicht geklappt hat

Code: Alles auswählen

Procedure TForm1.UpdateMyVehicles;
Var
  i: Integer;
Begin
  ListBox1.items.BeginUpdate;
  ListBox1.Clear;
  For i := 0 To high(MyVehicles) Do Begin
    ListBox1.Items.add(MyVehicles[i].NewFeature);
  End;
  ListBox1.items.EndUpdate;
End;    
Das kommt Heraus
demo.png
demo.png (11.87 KiB) 1784 mal betrachtet
Ich hätte aber erwartet dass da steht:
Demo_soll.png
Demo_soll.png (12.88 KiB) 1784 mal betrachtet
=> Mit Typehelpern gehts nicht, und Interfaces sind wohl ungeeignet.

Und Ja wenn ich folgenden Code schreibe gehts:

Code: Alles auswählen

Procedure TForm1.UpdateMyVehicles;
Var
  i: Integer;
Begin
  ListBox1.items.BeginUpdate;
  ListBox1.Clear;
  For i := 0 To high(MyVehicles) Do Begin
    If MyVehicles[i] Is TCar Then ListBox1.Items.add(TCar(MyVehicles[i]).NewFeature);
    If MyVehicles[i] Is TPlane Then ListBox1.Items.add(TPlane(MyVehicles[i]).NewFeature);
  End;
  ListBox1.items.EndUpdate;
End; 
Aber das finde ich halt doof, weil da so viele Vergleiche und Casts drin sind :/

Im Anhang habe ich euch nochmal das neue Beispiel das funktioniert rein gemacht ..
Dateianhänge
Demo2.zip
(2.99 KiB) 118-mal heruntergeladen
--
Just try it

Benutzeravatar
kupferstecher
Beiträge: 434
Registriert: Do 17. Nov 2016, 11:52

Re: Arbeiten mit Interfaces, wie macht man es korrect ?

Beitrag von kupferstecher »

Warum sollen Interfaces ungeeignet sein?

Code: Alles auswählen

Unit uExtended_Dont_Touch;

Type TExtendedCar = class(TCar,INewFeature)
    Function NewFeature: String;
End;

Type TExtendedPlane = class(TPlane,INewFeature)
    Function NewFeature: String;
End;
Nach corpsmans Hinweis korrigiert: INewFeature(MyVehicles).NewFeature => (MyVehicles as INewFeature).NewFeature

Code: Alles auswählen

For i := 0 To high(MyVehicles) Do Begin
    ListBox1.Items.add((MyVehicles[i] as INewFeature).NewFeature);
End;
Zuletzt geändert von kupferstecher am Do 15. Mai 2025, 21:33, insgesamt 1-mal geändert.

Warf
Beiträge: 2129
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Arbeiten mit Interfaces, wie macht man es korrect ?

Beitrag von Warf »

Also mit einem Interface kannst du keine Funktionalitäten hinzufügen. Ein Interface ist im Grunde ein "Versprechen". Indem du ein Interface implementierst versprichst du das deine Klasse alle Funktionen des Interfaces bereitstellt. Anderer Code kann dann dieses Versprechen einlösen ohne dabei wissen zu müssen wie die unterliegende Klasse aussieht.

Das Interface selbst stellt dabei aber keinen Code bereit, und es ist kein weg neuen Code mit einem bestehenden Typen zu assoziieren. Dafür gibt es Helper Typen. Damit kannst du einer Klasse neue Methoden zuordnen. Allerdings können Helper nicht das Speicherlayout von Typen verändern, und damit keine neuen Virtuellen Funktionen hinzufügen.

Wenn du Virtuelle Funktionen oder Felder Hinzufügen willst, dann musst du die Klasse anpassen.

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Arbeiten mit Interfaces, wie macht man es korrect ?

Beitrag von corpsman »

So also nach einigem Rumprobieren hab ich nun eine Lösung die "OK" ist, danke @kupferstecher

Hier meine Lösung:

1. uDoNotTouchMe wurde nicht verändert.
2. uExtended_Dont_Touch mit interfaces (Typehelper gehen ja nicht)

Code: Alles auswählen

Unit uExtended_Dont_Touch;

{$MODE ObjFPC}{$H+}

{$INTERFACES CORBA}

Interface

Uses
  Classes, SysUtils, uDoNotTouchMe;

Type
  INewFeatureInterface = Interface
    Function NewFeature(): String;
  End;

  { TNewFeatureVehicle }

  TNewFeatureVehicle = Class(TVehicle, INewFeatureInterface)
    Function NewFeature(): String; virtual;
  End;

  { TNewFeatureCar }

  TNewFeatureCar = Class(TCar, INewFeatureInterface)
    Function NewFeature(): String; virtual;
  End;

  { TNewFeaturePlane }

  TNewFeaturePlane = Class(TPlane, INewFeatureInterface)
    Function NewFeature(): String; virtual;
  End;

Implementation

Uses Dialogs;

{ TNewFeatureVehicle }

Function TNewFeatureVehicle.NewFeature(): String;
Begin
  result := '';
  Raise exception.create('base class ..');
End;

{ TNewFeatureCar }

Function TNewFeatureCar.NewFeature(): String;
Begin
  result := 'Car: ' + ClassName + ' Name:' + Name;
End;

{ TNewFeaturePlane }

Function TNewFeaturePlane.NewFeature(): String;
Begin
  result := 'Plane: ' + ClassName + ' Name:' + Name;
End;

End.

Im Projekt dann

Code: Alles auswählen

    MyVehicles: Array Of TVehicle;
Und bei der Benutzung:

Code: Alles auswählen


Procedure TForm1.UpdateMyVehicles;
Var
  i: Integer;
Begin
  ListBox1.items.BeginUpdate;
  ListBox1.Clear;
  For i := 0 To high(MyVehicles) Do Begin
    If MyVehicles[i] Is INewFeatureInterface Then Begin
      If MyVehicles[i] Is INewFeatureInterface Then Begin
        ListBox1.Items.add((MyVehicles[i] As INewFeatureInterface).NewFeature()); // Das geht
        // ListBox1.Items.add(INewFeatureInterface(MyVehicles[i]).NewFeature()); // -- Das geht nicht warum ?
      End;
    End;
  End;
  ListBox1.items.EndUpdate;
End;

Weis jemand warum der Typecast nicht geht ? Bisher dachte ich immer dass der Unterschied zwischen dem Typecast und des "as" Operators nur der ist, das beim "as" der Compiler im hintergrund eine "versteckte" Prüfung einbaut und ggf. ne Exception wirft sollte es nicht compatibel sein...
--
Just try it

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Arbeiten mit Interfaces, wie macht man es korrect ?

Beitrag von corpsman »

Arg, irgendwas läuft da schief.
Ich habe die neue Feature Klassen um ein 2. Interface erweitert:

Code: Alles auswählen

Unit uExtended_Dont_Touch;

{$MODE ObjFPC}{$H+}

{$INTERFACES CORBA}

Interface

Uses
  Classes, SysUtils, uDoNotTouchMe;

Type
  INewFeatureInterface = Interface
    Function NewFeature(): String;
  End;

  INewFeatureInterface2 = Interface
    Function NewFeature2(): String;
  End;

  { TNewFeatureCar }

  TNewFeatureCar = Class(TCar, INewFeatureInterface, INewFeatureInterface2)
    Function NewFeature(): String; virtual;
    Function NewFeature2(): String; virtual;
  End;

  { TNewFeaturePlane }

  TNewFeaturePlane = Class(TPlane, INewFeatureInterface, INewFeatureInterface2)
    Function NewFeature(): String; virtual;
    Function NewFeature2(): String; virtual;
  End;

Implementation

Uses Dialogs;

{ TNewFeatureCar }

Function TNewFeatureCar.NewFeature: String;
Begin
  result := 'Car: ' + ClassName + ' Name:' + Name;
End;

Function TNewFeatureCar.NewFeature2(): String;
Begin
  result := 'With feature2';
End;

{ TNewFeaturePlane }

Function TNewFeaturePlane.NewFeature: String;
Begin
  result := 'Plane: ' + ClassName + ' Name:' + Name;
End;

Function TNewFeaturePlane.NewFeature2(): String;
Begin
  result := 'With feature2';
End;

End.

Entsprechend den Aufruf erweitert:

Code: Alles auswählen

Procedure TForm1.UpdateMyVehicles;
Var
  i: Integer;
Begin
  ListBox1.items.BeginUpdate;
  ListBox1.Clear;
  For i := 0 To high(MyVehicles) Do Begin

    If MyVehicles[i] Is INewFeatureInterface Then Begin
      ListBox1.Items.add((MyVehicles[i] As INewFeatureInterface).NewFeature()); // Das geht
      // ListBox1.Items.add(INewFeatureInterface(MyVehicles[i]).NewFeature()); // -- Das geht nicht
    End;

    If MyVehicles[i] Is INewFeatureInterface2 Then Begin
      ListBox1.Items.add((MyVehicles[i] As INewFeatureInterface2).NewFeature2()); // Das geht
    End;
  End;
  ListBox1.items.EndUpdate;
End;
In der Listbox sieht es nun aber so aus als ob 2 mal "NewFeature" aufgerufen wurde, das ist irgendwie gar nicht gut. Ist das ein Bug oder hab ich wieder was nicht verstanden ?

[Edit]
Ahh die Lösung sind fehlende GUID's

Code: Alles auswählen

  INewFeatureInterface = Interface
    ['{bc9e1e1e-42ab-4ffa-803a-1536e7296127}'] // Created with https://www.guidgenerator.com/
    Function NewFeature(): String;
  End;

  INewFeatureInterface2 = Interface
    ['{c27e876a-3d67-4576-ae45-9b7a7c6b4ba1}'] // Created with https://www.guidgenerator.com/
    Function NewFeature2(): String;
  End; 
Und schon gehts ;)
--
Just try it

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6816
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Arbeiten mit Interfaces, wie macht man es korrect ? [Gelöst]

Beitrag von af0815 »

Zum Erzeugen einer GUID gibts in Lazarus einen Menüeintrag und, wenn ich richtig liege, sogar einen Shortcut.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Arbeiten mit Interfaces, wie macht man es korrect ? [Gelöst]

Beitrag von corpsman »

*g*,
ja ich weis, aber google war schneller ;)

by the way wenn ihr sehen wollt was ich daraus gemacht habe hier liegt die sourcedatei die das nun nutzt / nutzen wird. Hat schon seinen Charme das ganze ;)
--
Just try it

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6816
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Arbeiten mit Interfaces, wie macht man es korrect ? [Gelöst]

Beitrag von af0815 »

Es wäre nur schön, wenn keine Werbung für einen externen Generator drinnen wäre :shock: wenn es Lazarus selbst kann.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Antworten