![]() |
Delphi-Version: 5
"forward" von Units mit Record/Class Helpern
Hallo zusammen,
mangels besserer Bezeichnung nenne ich das was ich möchte mal "Unit forwarding", und zwar aus einem Base-Unit die Klassen in ein Interface-Unit übernehmen und re-deklarieren. So das nur noch das Interface-Unit in der Anwendung benutzt werden muss. Base-Unit
Delphi-Quellcode:
Interface-Unit
interface Pages.Types;
type TPage_Elem = (Eins, Zwei); // Hier werden diese Klassen etc. definiert TPage_Elem_Helper = record helper for TPage_Elem; // Hier kann es Helper geben procedure DoDomething; end; ... ...
Delphi-Quellcode:
und dann nur per Interface nutzen, während die Implementation in den Base-Units bleibt.
interface Pages;
Uses Pages.Types // Hier sind Klassen, Records, Enums, etc. definiert, s.o. ; type TPage_Elem = Pages.Types.TPage_Elem; // Hier werden diese Klassen etc. ge-forwared TPage_Elem_Helper = Pages.Types.TPage_Elem_Helper; // das möchte ich auch mit Helpern so machen
Delphi-Quellcode:
interface Main_Unit;
Uses Pages; // die Typen aus den Base-Units werden hier ge-forwarded und sind direkt nutzbar ... ... procedure Test; begin LElem := TPage_Elem.Eins; // Alles OK, kann ich benutzen mit Klassen, Records, Enums ... LElem.DoSomething // <-- ! Hier kann es nicht kompiliert werden, die Base-Units werden benötigt end; Gibt es da einen Trick wie man auch die Helper aus den Base-Units "forwarden" kann ? Oder ist sowas etwa ein schlechter Stil ? Rollo |
AW: "forward" von Units mit Record/Class Helpern
Spaßig dass es die Code Completion sogar vorschlägt, der Compiler aber dann aber nicht kann :stupid:
Ich sehe den Gefallen nicht denn man sich mit diesem "Forwarding" tut. Um sich eine Zeile im
Delphi-Quellcode:
zu sparen?
uses
|
AW: "forward" von Units mit Record/Class Helpern
Bei viel Modularisierung ist es eben nicht nur eine Unit, sondern vielleicht auch 5.
Das macht sich schon bemerkbar :stupid: |
AW: "forward" von Units mit Record/Class Helpern
Wenn du so etwas schon machen willst und es dann auch noch Interface nennst, dann solltest du am besten auch mit Interfaces arbeiten :wink:
Dann sprichst du das Thema Modularisierung an. Da bietet es sich auch gleich im Zusammenhang mit Interfaces an, mit Factories zu arbeiten. Schau dir das Thema mal an. Damit erreichst du eigentlich das was du willst und es wird noch modularer. Edit: Oh Moment ... du sprichst hier von Records :? Naja vielleicht bringt es dir trotzdem was oder du kannst auf Klassen umstellen. (Die benutze ich zumindest lieber als Records) |
AW: "forward" von Units mit Record/Class Helpern
Zitat:
PS: Ich kann es schon etwas verstehen wenn man den Helper für ein Enum vermisst, darum geht es ja eigentlich. Entweder inkludierst du die Unit wo der Helper drinsteckt, oder du verabschiedest dich ganz vom Enum und nimmst stattdessen gleich einen Record der ein Enum kapselt. Deinem Record kannst du nun Methoden verpassen und brauchst keinen Helper mehr. Durch Operator-Überladung kannst du dein altes Enum diesem Record zuweisen und umgekehrt...
Delphi-Quellcode:
und
type
TMyEnum = (uno, dos, tres); TMyEnumStruct = record Value: TMyEnum; function Next(): TMyEnumStruct; function Prev(): TMyEnumStruct; function ToString(): String; class operator Implicit(a: TMyEnumStruct): TMyEnum; class operator Implicit(a: TMyEnum): TMyEnumStruct; end;
Delphi-Quellcode:
procedure p();
var myEnum: TMyEnumStruct; begin myEnum := TMyEnum.dos; myEnum := myEnum.Next(); WriteLn( myEnum.ToString() ); end; |
AW: "forward" von Units mit Record/Class Helpern
@Aviator
Ich nenne es Interface weil auch eins drin ist. Die Helper sind Hilfs-Typen für das Interface. @Günther Mir ging es eigentlich im Wesentlichen um die Helper dabei. Die funktionieren nämlich weder bei Enum noch den anderen Sprachelementen. Ich möchte das Konzept so ja auch erstmal für mich einführen. Ich nenne das für mich "API", in der Hoffnung das ich komplexere Dinge simpel in der Anwenung zusammenfassen kann. Also z.B. Pages API die mir Alles für die Seitenverwaltung mitliefert, auch die Unterklassen, etc. Es geht mir um eine einfache Lernkurve dabei, wo man eben nicht Alle 5 Unter-Units genau kennen muss. Ich habe es bisher auch anders gelöst, und spiele gerade mit diesem Konzept etwas herum, und bin nur verwundert das ausgerechnet die Helper sich nicht "forwarden" lassen, der Rest der Elemente aber schon. Liegts an mir, oder an ... ? Rollo |
AW: "forward" von Units mit Record/Class Helpern
Zitat:
Aus
Delphi-Quellcode:
wird dann intern so etwas in der Art
type
TPage_Elem_Helper = record helper for TPage_Elem procedure DoSomething; end;
Delphi-Quellcode:
Damit der Compiler das auflösen kann, muss die Unit auch im uses erscheinen.procedure TPage_Elem_Helper_DoSomething(var Self: TPage_Elem); Es ist halt so, daß Helper nicht überall dort einsetzbar sind, wo andere Konstrukte funktionieren. Dies hier ist eben ein solcher Fall. |
AW: "forward" von Units mit Record/Class Helpern
Ich finde aber auch Helper sind ein Hilfsmittel, ein Notnagel oder ein bisschen Syntax-Zucker um Dinge lesbarer zu machen. Ein Helper ist, fast immer lokal auf die aktuelle Unit zugeschnitten.
Ich geb's ja zu, ich habe, genau wie du, auch oft Enums und direkt in der gleichen Unit gibt's noch den passenden Helper dazu, ob man will oder nicht. Aber das ganze mit einem Record kapseln - Ist zwar ein bisschen mehr tippen, aber sonst in jeder Hinsicht besser, oder? Dann nimmst du deine Methoden (und sogar Variablen) auch gleich "mitgeforwardet" mit ;-) |
AW: "forward" von Units mit Record/Class Helpern
Hallo Uwe,
ja dankesehr für die Erleuchtung, dann muss ich das Helper.forwarding wohl vergessen. @Der schöne Günther, Ok, das muss ich dann wohl so ähnlich machen. Ich arbeite bevorzugt mit Enums, weil die sich im Gegensatz zu Konstanten "automatisch" richtig verhalten in den meisten Fällen, und super leicht erweiterbar sind. Solche Enums ersetzen bei mir fast alle "Magic-Numbers". Mit dem einbau in Records: Meinst du das Beste aus beiden Welten (enum/record-class) zu kombinieren ? So in etwa:
Delphi-Quellcode:
Das funktioniert, kapselt die Enums, hat aber den Charme der simplen Helper etwas verloren :-(
type
TTest_Record_Level2 = record public type TEnum = (COneHundret = 1, CTwoHundret, CThreeHundret); public class function OneHundret : TTest_Record_Level2.TEnum; {inline;} static; // inline needs Base unit class function TwoHundret : TTest_Record_Level2.TEnum; {inline;} static; class function ThreHundret : TTest_Record_Level2.TEnum; {inline;} static; class function ToInteger(const AEnum : TTest_Record_Level2.TEnum) : Integer; static; end; ... ... ... class function TTest_Record_Level2.OneHundret: TTest_Record_Level2.TEnum; begin Result := TTest_Record_Level2.TEnum.COneHundret; end; class function TTest_Record_Level2.ThreHundret: TTest_Record_Level2.TEnum; begin Result := TTest_Record_Level2.TEnum.CTwoHundret; end; class function TTest_Record_Level2.TwoHundret: TTest_Record_Level2.TEnum; begin Result := TTest_Record_Level2.TEnum.CThreeHundret; end; class function TTest_Record_Level2.ToInteger(const AEnum: TTest_Record_Level2.TEnum): Integer; begin Result := Integer( AEnum ) * 100; end; ... ... ... procedure TForm1.Button5Click(Sender: TObject); var LEnum : TTest_Record_Level2.TEnum; LInt: Integer; begin LEnum := TTest_Record_Level2.OneHundret; LInt := TTest_Record_Level2.ToInteger( LEnum ); if LEnum = TTest_Record_Level2.OneHundret then begin LEnum := TTest_Record_Level2.TwoHundret; LInt := TTest_Record_Level2.ToInteger( LEnum ); end; end; Kann man auch gleich class helper statt record helper nehmen, ist aber womöglich kein Unterschied.
Delphi-Quellcode:
Wobei man die Funktionen auch weglassen, und direkt mit dem TEnum arbeiten kann.
class function OneHundret : TTest_Record_Level2.TEnum; {inline;} static;
class function TwoHundret : TTest_Record_Level2.TEnum; {inline;} static; class function ThreHundret : TTest_Record_Level2.TEnum; {inline;} static; Das mache ich z.T. bei einigen Klassen schon so. Der Vorteil wäre wohl beim besseren AutoComplete, und das die Funktionen auch etwas mehr machen könnten als nur Werterückgabe.
Delphi-Quellcode:
class function OneHundret : TTest_Record_Level2.TEnum; {inline;} static; // inline
Inline geht beim "forwarden" leider auch nicht, weil dann auch die Base-Units gebraucht werden (nicht zum Kompilieren, aber um 0 warnings zu Erreichen). Stilfrage: Da wäre dann noch die Frage zum Stil des "Unit-Forwarding". Ich habe ja schon gehört das dies Einige nicht gut finden, ich sehe da nur ein Problem das man "versteckte" Abhängigkeiten bekommt, im Gegensatz zu "offen sichtbaren" Abhängigkeiten in den uses. Sonst sehe ich da keine anderen grundsätzlichen Probleme, oder gibt es die etwa doch ? Rollo |
AW: "forward" von Units mit Record/Class Helpern
Zitat:
Was verstehst du denn unter einer "versteckten" Abhängigkeit? Ich verstehe darunter eigentlich genau das, was eben durch dieses "Typ-Forwarding" ausgelöst wird: Man nutzt ja schon die Basis-Unit, gibt sie aber nicht in der Uses-Anweisung an. Man ist also abhängig von der Basis-Unit, sieht es aber nicht gleich. Die besagte inline-Warnung zeigt das ganz deutlich: Sie ist ja nicht nur eine Warnung, sondern der Compiler erzeugt dann auch anderen Code (nämlich non-inlined). Du bekommst also dasselbe wie ohne das inline. Der Compiler tut einfach so als wäre es nicht da. |
AW: "forward" von Units mit Record/Class Helpern
Zitat:
Weil ich ja auch sonst nicht immer "perfekt" ordentlich bin kann ich das für mich akzeptieren. Da wiegt bei mir das ease-of-use höher. Ich dachte vielleicht verstößt aber so ein "unit-forwarding" noch gegen irgendeine sonstige Code-Design oder Code-Pattern-Regel, die ich noch nicht kenne. Rollo |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:42 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