Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Fehlende Mehrfachvererbung bei Schnittstellen (https://www.delphipraxis.net/181132-fehlende-mehrfachvererbung-bei-schnittstellen.html)

Uwe Raabe 17. Jul 2014 21:31

AW: Fehlende Mehrfachvererbung bei Schnittstellen
 
Jetzt mal etwas out-of-the-box gedacht (weiß nicht, ob das hier taugt):

Delphi-Quellcode:
type
  IBase = interface
  end;

  ISub1 = interface (IBase)
  end;

  ISub2 = interface (IBase)
  end;

  IBoth = interface
    function GetSub1: ISub1;
    function GetSub2: ISub2;
    property Sub1: ISub1 read GetSub1;
    property Sub2: ISub2 read GetSub2;
  end;

type
  TFluxKompensator = class(TInterfacedObject, ISub1, ISub2, IBoth)
    function GetSub1: ISub1;
    function GetSub2: ISub2;
  end;

function TFluxKompensator.GetSub1: ISub1;
begin
  result := Self;
end;

function TFluxKompensator.GetSub2: ISub2;
begin
  result := Self;
end;

Stevie 17. Jul 2014 22:35

AW: Fehlende Mehrfachvererbung bei Schnittstellen
 
Ich hab grad son Deja Vu, das Thema hatten wir doch neulich erst :gruebel:

Generell stell ich mir immer die Frage, warum man vom einen Interface auf ein anderes kommen sollte. Das ISP gibt's ja nicht umsonst.

Wenn also ein Programmteil
Delphi-Quellcode:
IDiesesDings
konsumiert, warum sollte es dann darauf schauen, ob das Objekt dahinter nich auch zufällig noch
Delphi-Quellcode:
IJenesDings
implementiert und damit was machen. Klar, mag es Fälle geben, aber generell ist das eher ein Architektursmell, wenn man sowas braucht. Das geht ein wenig in die Richtung Leaky Abstraction.

Patito 18. Jul 2014 07:42

AW: Fehlende Mehrfachvererbung bei Schnittstellen
 
Zitat:

Zitat von Stevie (Beitrag 1265850)
Ich hab grad son Deja Vu, das Thema hatten wir doch neulich erst :gruebel:

Generell stell ich mir immer die Frage, warum man vom einen Interface auf ein anderes kommen sollte. Das ISP gibt's ja nicht umsonst.

Bei Mehrfachvererbung will man auf einen bekannten Parent casten können. (Man will z.B. ein Interface
als Parameter an eine Prozeduren übergeben können, die als Parameter ein ParentInterface erwartet).

Das ISP will, dass man nicht unnötig große Schnittstellen übergiebt, und genau das ist es, was der Cast auf den Parent macht.
Leider geht das in Delphi eben nicht ganz ohne Bastelei, daher ist sowas leider immer wieder ein Thema...

Der schöne Günther 18. Jul 2014 08:04

AW: Fehlende Mehrfachvererbung bei Schnittstellen
 
Vielen Dank für die ganzen schlauen Beiträge. :cheers:

Ich glaube die Beiträge von Uwe und BUG sind in Sachen Lösung wohl das, worauf es in Delphi am besten hinausläuft.

Sir Rufo 18. Jul 2014 08:38

AW: Fehlende Mehrfachvererbung bei Schnittstellen
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1265862)
Vielen Dank für die ganzen schlauen Beiträge. :cheers:

Ich glaube die Beiträge von Uwe und BUG sind in Sachen Lösung wohl das, worauf es in Delphi am besten hinausläuft.

Also sind wir wieder (oder immer noch) da, wo wir im Januar Juni waren http://www.delphipraxis.net/1261684-post24.html ;)

Der schöne Günther 18. Jul 2014 09:24

AW: Fehlende Mehrfachvererbung bei Schnittstellen
 
Ich wollte, mit einem mehr oder weniger konkreten Beispiel, schauen, wie andere es schreiben würden.

Das andere Thema geht ja eher (technisch) darum zu schauen, was und was nicht in Delphi geht; mit dem Fokus auf das "Herausfinden, das etwas implementiert wird". Mir ging es jetzt nicht um das Herausfinden, sondern um das "Wie am besten ansprechen?".

Und wieso Januar?

Stevie 18. Jul 2014 10:01

AW: Fehlende Mehrfachvererbung bei Schnittstellen
 
Zitat:

Zitat von Patito (Beitrag 1265859)
Bei Mehrfachvererbung will man auf einen bekannten Parent casten können. (Man will z.B. ein Interface
als Parameter an eine Prozeduren übergeben können, die als Parameter ein ParentInterface erwartet).

Bei diesem Usecase stimme ich dir zu.

Zitat:

Zitat von Patito (Beitrag 1265859)
Leider geht das in Delphi eben nicht ganz ohne Bastelei, daher ist sowas leider immer wieder ein Thema...

Als große Bastelei würd ich es nicht bezeichnen, allerdings kann man es nicht designtechnisch 100%ig sauber lösen,
da es ein Implementierungsdetail wird und nicht über die Interfacedefinition ersichtlich ist.
Zudem hat man leider keine Compile time safety.

Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  IBar = interface
    ['{F2BDC6D3-6E79-48EF-99A9-94DE53C035DC}']
    procedure DoIt;
  end;

  IBaz = interface
    ['{3E99A294-48EF-4E2A-B077-562462997EA7}']
    procedure DoIt;
  end;

  IFoo = interface{(IBar, IBaz)}
    ['{F2173B9B-43A5-4631-A08B-7D64102F1867}']
  end;

  TFoo = class(TInterfacedObject, IBar, IBaz, IFoo) // in C#: Foo : IFoo
  protected
    procedure DoIt;
  end;

procedure TFoo.DoIt;
begin
  Writeln('DoIt')
end;

procedure DoSomething(const bar: IBar);
begin
  bar.DoIt;
end;

var
  foo: IFoo;
begin
  foo := TFoo.Create;
  DoSomething(foo as IBar);
  Readln;
end.
P.S: Ich hab mich gerade mal mit meinem Kollegen zusammen gesetzt, der C# beherrscht und uns angeschaut, was diese "Multiple Interface Inheritance" in C# so macht.
Wir sind zu dem Schluss gekommen, dass es letztlich nur Syntax Sugar ist, was dafür sorgt, dass eine Klasse die ein Interface implementiert, welches von verschiedenen anderen "abgeleitet" ist, diese auch implementiert. Auch beim Übergeben eines solchen Interfaces an eine Methode, welche eins der Elterninterfaces erwartet, benötigt man dann keinen Cast, sondern kann es so übergeben. Letztlich ist es aber dasselbe wie ich oben im Delphi Code geschrieben habe, nur ein wenig typensicherer.

Im Übrigen lässt C# ein foo.DoIt() nicht zu und quittiert es mit einem "ambiguous call" Compilerfehler.
Und auch die Reflection zeigt einem, dass die Klasse alle 3 Interfaces implementiert, obwohl man eigentlich nur IFoo hingeschrieben hat.

Blup 18. Jul 2014 12:07

AW: Fehlende Mehrfachvererbung bei Schnittstellen
 
Danke, du hast den Problemkreis sehr anschaulich beschrieben.
Der Delphicompiler müsste nur zwei Dinge zusätzliche beherschen:
Delphi-Quellcode:
TFoo = class(TInterfacedObject, IFoo) // IBar, IBaz, alle Eltern durch den Compiler versteckt mit angelegt} 

DoSomething(foo); // (foo as IBar) duch den Compiler automatische Abfrage des passenden Elter
Das vermisse ich eigentlich schon fast so lange, wie ich mit Interfaces in Delphi arbeite.

Sir Rufo 18. Jul 2014 12:24

AW: Fehlende Mehrfachvererbung bei Schnittstellen
 
Zitat:

Zitat von Blup (Beitrag 1265893)
Danke, du hast den Problemkreis sehr anschaulich beschrieben.
Der Delphicompiler müsste nur zwei Dinge zusätzliche beherschen:
Delphi-Quellcode:
TFoo = class(TInterfacedObject, IFoo) // IBar, IBaz, alle Eltern durch den Compiler versteckt mit angelegt} 

DoSomething(foo); // (foo as IBar) duch den Compiler automatische Abfrage des passenden Elter
Das vermisse ich eigentlich schon fast so lange, wie ich mit Interfaces in Delphi arbeite.

Es geht ja mit Delphi schon so:
Delphi-Quellcode:
procedure DoSomethingWithBar( ABar : IBar );
procedure DoSomethingWithBaz( ABaz : IBaz );

TFoo = class( TInterfacedObject, IBar, IBaz, IFoo )
...
end;

var
  Foo : TFoo;
begin
  Foo := TFoo.Create;
  DoSomethingWithBar( Foo );
  DoSomethingWithBaz( Foo );
end;
Das Hauptproblem ist aber hierbei, dass nach dem Aufruf von
Delphi-Quellcode:
DoSomethingWithBar( Foo );
die Foo-Instanz sich in Rauch auflöst. Somit müsste man entweder
Delphi-Quellcode:
TFoo
von
Delphi-Quellcode:
TPersistentInterface
ableiten und explizit freigeben
Delphi-Quellcode:
TFoo = class( TInterfacedPersistent, IBar, IBaz, IFoo )
end;

var
  Foo : TFoo;
begin
  Foo := TFoo.Create;
  try
    DoSomethingWithBar( Foo );
    DoSomethingWithBaz( Foo );
  finally
    Foo.Free;
  end;
end;
oder sich eben zusätzlich eine
Delphi-Quellcode:
IFoo
Referenz merken.
Delphi-Quellcode:
var
  Foo : TFoo;
  FooIntf : IFoo;
begin
  Foo := TFoo.Create;
  FooIntf := Foo;
  DoSomethingWithBar( Foo );
  DoSomethingWithBaz( Foo );
end;
oder man hat ARC und dann klappt es einfach so ohne dieses Gedöns.

Stevie 18. Jul 2014 20:13

AW: Fehlende Mehrfachvererbung bei Schnittstellen
 
Zitat:

Zitat von Sir Rufo (Beitrag 1265896)
Es geht ja mit Delphi schon so:
Delphi-Quellcode:
*snip*

Das hast du dir aber nur so hingebogen, weil foo von
Delphi-Quellcode:
TFoo
ist und nicht wie im Beispiel oben von
Delphi-Quellcode:
IFoo
, worum es auch hier eigentlich geht.

Ich kann dir nicht sagen, was C# da genau macht, wenn man ein IFoo an ein IBar oder IBaz übergibt (hab mir den IL Code nicht angeschaut). Aber dadurch, dass dort fest steht, "wenn IFoo implementiert wird, dann ist auch IBar und IBaz implementiert" ist sichergestellt, dass ein Cast von IFoo auf IBar oder IBaz immer erfolgreich ist.

Und genau das geht in Delphi ebend nicht.

Zitat:

Zitat von Blup (Beitrag 1265893)
Der Delphicompiler müsste nur zwei Dinge zusätzliche beherschen:
Delphi-Quellcode:
TFoo = class(TInterfacedObject, IFoo) // IBar, IBaz, alle Eltern durch den Compiler versteckt mit angelegt} 

DoSomething(foo); // (foo as IBar) duch den Compiler automatische Abfrage des passenden Elter
Das vermisse ich eigentlich schon fast so lange, wie ich mit Interfaces in Delphi arbeite.

Exakt. Ich werd mal nachfragen, ob sowas mal angegangen werden könnte.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:12 Uhr.
Seite 2 von 3     12 3      

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