![]() |
Delphi-Version: XE7
Class Helper for Interface
Man kann doch Class/Record Helper nun an "alles" dran hängen?
Warum nicht auch an Interfaces? |
AW: Class Helper for Interface
Weil Embarcadero einfach zu be... ach, lassen wir das, sonst reg ich mich nur wieder auf...
|
AW: Class Helper for Interface
Class Helper sind doch dazu gedacht, eine Klasse nachträglich etwas zu pimpen.
Interfaces sind Verträge. Wieso sollte ich Verträge nachträglich noch aufbohren wollen. Dann passt das doch nicht mehr. Wo ist mein Denkfehler? |
AW: Class Helper for Interface
Berühmtestes Beispiel: IEnumerable<T>
Eigentlich müsste dieses Interface nur so aussehen:
Delphi-Quellcode:
Und über Extension Methodseinen interface helper kann man nun alle möglichen Operationen, die auf GetEnumerator operieren, implementieren.
type
IEnumerable<T> = interface function GetEnumerator: IEnumerator<T> end; Das ermöglicht einem eine Verkettung dieser Operationen -> syntax Sugar. Anderes Beispiel:
Delphi-Quellcode:
Simples Interface, wenn man neue Logger bauen will, muss man nur eine Methode implementieren -> gut!
type
ILogger = interface procedure WriteLogEntry(const entry: TLogEntry); end; Aber den Logger zu benutzen ist nun eher umständlich, denn es mag nun verschiedene Eigenschaften in TLogEntry geben, die ich immer befüllen muss. Also würde sich so ein Interface helper anbieten:
Delphi-Quellcode:
In diesen Methoden wird nun nix anderes gemacht als die Information in ein TLogEntry gepackt und dann an die WriteLogEntry Methode übergeben.
type
ILoggerHelper = interface helper for ILogger procedure LogValue<T>(const value: T) procedure EnterMethod(const methodName: string); procedure LeaveMethod(const methodName: string); end; D.h. ich kann die Funktionalität des Interfaces erweitern, ohne den Vertrag zu verletzen und ohne weitere Kopplung für den Implementierenden zu erzeugen. Im Grunde sind so helper Methoden nix anderes als das:
Delphi-Quellcode:
Aber ein:
procedure Methode(Self: <gehelpter type>; args)
Delphi-Quellcode:
Und umso mehr, wenn ich solche Methoden verketten kann (ja, das geht mit Spring4D aber auch nur, weil die ganzen Methoden auf IEnumerable<T> sitzen und somit dem Implementierer aufgezwungen werden, obwohl sie nur auf GetEnumerator aufsetzen -> fette Klassen):
logger.EnterMethod('foo');
// liest sich einfach besser als: EnterMethod(logger, 'foo');
Delphi-Quellcode:
for c in customers.Where(...).Ordered.Take(10) do
// mach was |
AW: Class Helper for Interface
Aber warum nicht einfach
Delphi-Quellcode:
?
ILoggerHelper = interface(ILogger)
|
AW: Class Helper for Interface
Zitat:
Ja, Dekorator bauen, etc... aber darum gehts nicht. Außerdem könnte ich, wären die helper vernünftig implementiert auch mehrere gleichzeitig aktiv haben, mach das mal mit Vererbung Eine mögliche Syntax die ich mir auch vorstellen könnte wäre sowas (woher ich das wohl habe...):
Code:
Und die kann man dann so aufrufen:
procedure EnterMethod(extends logger: ILogger; const methodName: string);
Code:
Simpler Syntaxzucker also. Und wenn ich das gerade richtig überblicke dürften dort auch alle Regeln von normalen Routinen (sprich, welche Methode ist im Scope, Overload resolution etc) greifen.
logger.EnterMethod('foo')
|
AW: Class Helper for Interface
Bei der Gelegenheit könnte man gleich noch eine Diskussion über, seit Java 8 vorhandene, Standard-Implementierungen für Interfaces anstoßen: Ein Interface kann eine Standard-Implementierung einer Methode sowie statische Methoden vorgeben. Im Endeffekt geht das ja in eine stark ähnliche Richtung.
Würdet ihr, so etwas gerne in Delphi sehen wollen? Ich dachte erst "Was für ein Quatsch" aber in der Zwischenzeit bin ich auch über ein paar Fälle gestolpert wo man das hätte gebrauchen können... |
AW: Class Helper for Interface
Unter Delphi ist das mit den Interface Helpern doch uninteressant, denn die Interfaces unterstützen keine Generics
Delphi-Quellcode:
Mit einem
IFoo<T> = interface
function AsType<TResult> : TResult; // <- Zonk end;
Delphi-Quellcode:
drumherum ist das dann wieder kein Problem (ist ja in Spring4D auch so vorhanden ;))
record
Delphi-Quellcode:
Wenn also diese Schranke fällt, dann ist auch der Interface Helper interessant. Bis dahin müsste man sich je nach Fall immer zwischen Interface Helper oder eben doch Record entscheiden. Dann doch lieber immer auf die gleiche Weise
Foo<T> = record
class operator implicit ( a : IFoo<T> ) : Foo<T>; function AsType<TResult> : TResult; end; |
AW: Class Helper for Interface
Zitat:
Im Grunde geht es genau um das, wozu diese Helper erfunden wurden. Das "erweitern" der Funktionen, von irgedwas (Klasse/Record/Typ), ohne diesen Typen direkt zu verändern. Bei Klassen kann man einfach vererben, aber bei Interfaces geht das nicht, denn dort muß man das "Objekt" hinter dem Interface verändern/kapseln und Funktionsaufrufe an das originale Interface weiterreichen. Man kann ein eigenes Objekt schreiben, daß beim QueryInterface die Zugriff auf das/die originalen Interfaces weitergibt, aber rückwärts geht das nicht, daß das "fremde" Objekt mein Interface nicht kennt. Dazumal sind das zwei getrennten Objekte und die Referenzzählung/Freigabe ist nicht lösbar, ohne das andere Interface komplett zu kapseln. |
AW: Class Helper for Interface
Zitat:
Dass es keine generischen Methoden auf Interface selber gibt, hat einen technischen Grund, nämlich den gleichen, warum es keine virtuellen Methoden mit generischen Parametern gibt: ich hab nur einen Slot in der VMT dafür, für welches T soll ich den nehmen? Methoden in einem Interface Helper wären aber nicht virtuell. Viel schlimmer: man kann aktuell keine helper für generische Typen bauen! Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:30 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