![]() |
AW: Interface-Unterstützung
Zitat:
Muss ich dann in jede Klasse und das dort pasten, damit er ne simple Signatur updatet oder neue Methoden hinufügt? |
AW: Interface-Unterstützung
Zitat:
Ich könnte mir aber vorstellen, daß MMX die implementierenden Klassen zumindest im aktuellen Projekt/Projektgruppe automatisch ausfindig macht und eine Synchronisierung anbietet oder optional automatisch durchführt. Wäre zumindest einen Feature-Request wert. |
AW: Interface-Unterstützung
Hier nochmal ein neuer Zwischenstand.
Im ersten Text ist verkürzt eine Klasse deklariert und nach Tastendruck wird daraus das nachfolgende Ergebnis generiert. Es geht noch nicht alles, aber die Idee dahinter sollte schon mal gut erkennbar sein. Es werden die Methoden, Properties und privaten Felder erzeugt und auch die Methoden soweit möglich vorausgefüllt. Das natürlich nur, wenn sie neu generiert werden. Spätere händische Änderungen bleiben natürlich bei künftigen Optimierungen erhalten. Der Implementationsteil wird analog dem Interfaceteil sortiert. Das gilt auch, wenn die Reihenfolge der Klassen oder Klassenmember im Interfaceteil nachträglich verändert wird. Bei der nächsten Optimierung werden dann die Klassen und Methoden im Implementationsteil an die neue Reihenfolge im Interfaceteil angepasst. Derzeit habe ich die Getter und Setter mit _get_... und _set_ benannt und die privaten Felder mit "f". Außerdem habe ich in generierten Methoden ein ? eingesetzt, damit man die Methoden mindestens einmal bearbeitet. In Settern prüfe ich erst auf eine Werteänderung. Das alles lässt sich natürlich ggf. auch über Optionen steuern, falls daran Bedarf wäre. Original:
Delphi-Quellcode:
unit Unit2;
interface uses System.Classes, Vcl.Graphics, System.Types, System.UITypes; const aConst = 100; type TClass1 = class private procedure PrivProc; virtual; public constructor Create; virtual; destructor Destroy; override; public procedure Execute(NewVal: String); virtual; function TestFunc(var Val1: Integer): Boolean; prop PropString: string; prop PropInteger: Integer rf; prop PropBoolean: Boolean v ws vi; prop PropByte: Byte s; prop PropWord: Word c w rf; prop PropString2: string c vi; end; implementation end. Ergebnis:
Delphi-Quellcode:
unit Unit2;
interface uses System.Classes, Vcl.Graphics, System.Types, System.UITypes; const aConst = 100; type TClass1 = class private fPropString: string; fPropInteger: Integer; fPropBoolean: Boolean; fPropByte: Byte; fPropWord: Word; fPropString2: string; procedure PrivProc; virtual; function _get_PropString: string; procedure _set_PropString(aValue: string); procedure _set_PropBoolean(var aValue: Boolean); virtual; function _get_PropByte: Byte; stdcall; procedure _set_PropByte(aValue: Byte); stdcall; function _get_PropString2: string; virtual; procedure _set_PropString2(const aValue: string); virtual; public constructor Create; virtual; destructor Destroy; override; procedure Execute(NewVal: String); virtual; function TestFunc(var Val1: Integer) Boolean property PropString: string read _get_PropString write _set_PropString; property PropInteger: Integer read fPropInteger; property PropBoolean: Boolean write _set_PropBoolean; property PropByte: Byte read _get_PropByte write _set_PropByte; property PropWord: Word read fPropWord; property PropString2: string read _get_PropString2 write _set_PropString2; end; implementation { TClass1 } constructor TClass1.Create; begin end; destructor TClass1.Destroy; begin end procedure TClass1.PrivProc; begin ?; end function TClass1._get_PropString: string; begin Result := fPropString; end procedure TClass1._set_PropString(aValue: string); begin if (fPropString <> aValue) then begin fPropString := aValue; end; end procedure TClass1._set_PropBoolean(var aValue: Boolean); begin if (fPropBoolean <> aValue) then begin fPropBoolean := aValue; end; end function TClass1._get_PropByte: Byte; begin Result := fPropByte; end procedure TClass1._set_PropByte(aValue: Byte); begin if (fPropByte <> aValue) then begin fPropByte := aValue; end; end function TClass1._get_PropString2: string; begin Result := fPropString2; end procedure TClass1._set_PropString2(const aValue: string); begin if (fPropString2 <> aValue) then begin fPropString2 := aValue; end; end procedure TClass1.Execute(NewVal: String); begin ?; end function TClass1.TestFunc(var Val1: Integer): Boolean; begin Result := ?; end end. Als nächstes will ich jetzt die Optimierung von Interfaces und von Klassen, die Interfaces verwenden, umsetzen. Dann würden entsprechende Deklarationen wie oben im Interface automatisch auf die das Interface verwendenden Klassen durchschlagen. In der Klasse gäbe es dann Sektionen wie
Delphi-Quellcode:
Spätere Änderungen im Interface würden automatisch auf die Klassen durchschlagen. Das wird (mit einer entsprechenden Anweisung) sogar für Umbenennungen von Properties und Methoden möglich sein, so dass eine InterfaceMember-Namensänderung nacheinander in mehreren Projekten nacheinander automatisiert durchgeführt werden kann (allerdings dann wohl nur bei den Klassenmembern, nicht als wirkliches Refactoring).
private // Intf1
fProp: Integer protected // Intf1 function _get_Prop: Integer; public // Intf1 property Prop: Integer read _get_Prop; Wird das jetzt interessanter? |
AW: Interface-Unterstützung
Für mich Nein, sorry. Ich nehm meist den MMX für so was.
Übrigens habe ich mir auch ein Tool für DTO-Datenklassen gemacht. Man schreibt ein interface (mit oder ohne Getter) und das Tool ergänzt die interfaces, erstellt die Klassen die das implementieren und dazu noch Fabrikmethoden und auf Wunsch records dazu. |
AW: Interface-Unterstützung
Zitat:
Dass da immer wieder jemand sein eigenes Süppchen kocht, ist echt suboptimal. Da das ein Tool vor allem für dich selbst ist, bist du da natürlich frei, aber so wird es dann wohl auch eher eine Lösung bleiben, die sonst nicht viele nutzen möchten. Gerade die Verwendung von Standards ist in vielen Bereichen wirklich hilfreich (und trägt zur Verbreitung einer Lösung bei)... Was ich tatsächlich nützlich finden würde, wäre, wenn man die Property normal hinschreiben könnte ohne read und write und dann analog zur Klassenvervollständigung Getter und Setter ergänzt würden. Wie ich das aktuell mache, hatte ich ja schon geschrieben: ![]() Das geht zwar sehr schnell, auch bei mehreren Properties, aber wenn das in einem Schritt ginge, wäre das schon schön. Mit deiner Kurzschreibweise kann ich mich leider gar nicht anfreunden. Die paar Millisekunden Zeitersparnis beim Tippen (prop vs. property) sind für mich nicht relevant, da schreibe ich es lieber richtig... Wenn statt
Delphi-Quellcode:
das ganze auch mit
prop PropString: string;
Delphi-Quellcode:
gehen würde, wäre das schon gut. Dann könnte es eine Alternative zur Klassenvervollständigung werden.
property PropString: string;
Trotzdem geht mit MMX aktuell noch deutlich mehr. |
AW: Interface-Unterstützung
@freimatz
Ich hatte auch mal einen Codegenerator, der mir anhand von Datenstrukturen komplette Klassen erstellt hat. Das ist aber nicht vergleichbar mit der Änderung einer bestehenden Unit. Kann Dein Tool so etwas auch? Ich würde es dann gerne übernehmen, wobei ich mit meinem jetzt auch schon recht weit und zufrieden bin. @jaenicke _get_ und _set_ verwende ich gern, weil Getter und Setter ja eher Hilfskonstrukte sind, die normalerweise nicht extern aufgerufen werden. So sind "echte Funktionen" wie GetBestFriends(1000) durch die Namensgebung besser von Gettern und Settern zu unterscheiden. Aber wie gesagt, das ließe sich ja völlig unproblematisch über Optionen steuern. Auch "property" auf Wunsch auszuschreiben wäre kein Problem. Die Codevervollständigung würde dann analog "prop" zuschlagen, wenn darauf kein read und kein write folgt (sonst wäre das Property ja schon mit einem read und/oder write vollständig deklariert und dürfte nicht mehr automatisch verändert werden). Klar ist der MMX komplexer, mir aber zu umständlich. Mein Tool sehe ich einfach als Codevervollständigung 2.0 + UnitSortierer. Meiner Arbeitsweise kommt das (wenn es fertig wird, wie erhofft) sehr viel mehr entgegen. Wenn man in Interfaces oder im Interfaceteil von Klassen bestimmte Vorgaben trifft, ergibt sich daraus bereits exakt, was an anderen Stellen nochmal exakt so geschrieben werden muss. Und genau das nervt mich inzwischen extrem. |
AW: Interface-Unterstützung
Mein Tool ist nicht unviversell brauchbar. Erstmal ist er nur für Transferobjekte da. Weiter wird formatierter Code verlangt so wie es unser Formatter macht. Dann ist das Tool ein Gebastel und mit <duck>VS/C#</duck> erstellt. Neuerdings sollte das Tool auch mit bestehenden units klar kommen.
Zum Verständnis noch ein Beispiel: Gegeben
Delphi-Quellcode:
Dann wird da draus:
IBlafaselCalculatorSourceData = interface(IBlaCalculatorSourceData)
['{FDFBCC49-C16F-4BC1-B6BF-7926EA37113F}'] property ToleranceZoneGeometry: IToleranceZoneGeometryBase; property PreparedPoints: TPreparedPoints; end;
Delphi-Quellcode:
Der Record ist hier noch nicht dabei. Auch etliche REGIONS habe ich weggelassen.
IBlafaselCalculatorSourceData = interface(IBlaCalculatorSourceData)
['{FDFBCC49-C16F-4BC1-B6BF-7926EA37113F}'] function GetToleranceZoneGeometry(): IToleranceZoneGeometryBase; function GetPreparedPoints(): TPreparedPoints; property ToleranceZoneGeometry: IToleranceZoneGeometryBase read GetToleranceZoneGeometry; property PreparedPoints: TPreparedPoints read GetPreparedPoints; end; ... function CreateBlafaselCalculatorSourceData( ... Zeug von Vorfahre const p_ToleranceZoneGeometry: IToleranceZoneGeometryBase; const p_PreparedPoints : TPreparedPoints): IBlafaselCalculatorSourceData; ... TBlafaselCalculatorSourceData = class(TBlaCalculatorSourceData, IBlafaselCalculatorSourceData) strict private FToleranceZoneGeometry: IToleranceZoneGeometryBase; FPreparedPoints : TPreparedPoints; function GetToleranceZoneGeometry(): IToleranceZoneGeometryBase; function GetPreparedPoints(): TPreparedPoints; public constructor Create( ... Zeug von Vorfahre const p_ToleranceZoneGeometry: IToleranceZoneGeometryBase; const p_PreparedPoints : TPreparedPoints); property ToleranceZoneGeometry: IToleranceZoneGeometryBase read GetToleranceZoneGeometry; property PreparedPoints: TPreparedPoints read GetPreparedPoints; end; ... constructor TBlafaselCalculatorSourceData.Create( ... Zeug von Vorfahre const p_ToleranceZoneGeometry: IToleranceZoneGeometryBase; const p_PreparedPoints : TPreparedPoints); begin inherited Create(... Zeug von Vorfahre); FToleranceZoneGeometry := p_ToleranceZoneGeometry; FPreparedPoints := p_PreparedPoints; end; ... constructor TBlafaselCalculatorSourceData.Create( ... Zeug von Vorfahre const p_ToleranceZoneGeometry: IToleranceZoneGeometryBase; const p_PreparedPoints : TPreparedPoints); begin inherited Create(... Zeug von Vorfahre); FToleranceZoneGeometry := p_ToleranceZoneGeometry; FPreparedPoints := p_PreparedPoints; end; ... constructor TBlafaselCalculatorSourceData.Create( ... Zeug von Vorfahre const p_ToleranceZoneGeometry: IToleranceZoneGeometryBase; const p_PreparedPoints : TPreparedPoints); begin inherited Create(... Zeug von Vorfahre); FToleranceZoneGeometry := p_ToleranceZoneGeometry; FPreparedPoints := p_PreparedPoints; end; function TBlafaselCalculatorSourceData.GetToleranceZoneGeometry(): IToleranceZoneGeometryBase; begin Result := FToleranceZoneGeometry; end; function TBlafaselCalculatorSourceData.GetPreparedPoints(): TPreparedPoints; begin Result := FPreparedPoints; end; ... function CreateBlafaselCalculatorSourceData( ... Zeug von Vorfahre const p_ToleranceZoneGeometry: IToleranceZoneGeometryBase; const p_PreparedPoints : TPreparedPoints): IBlafaselCalculatorSourceData; begin Result := TBlafaselCalculatorSourceData.Create(... Zeug von Vorfahre, p_ToleranceZoneGeometry, p_PreparedPoints); end; |
AW: Interface-Unterstützung
Liste der Anhänge anzeigen (Anzahl: 1)
Ich habe jetzt noch einen neuen Ansatz realisiert.
Das Tool analysiert die zusammenhängenden Blöcke und kennzeichnet sie farblich. (Umgebaut wird die Unit noch nicht.) Es ist doch überraschend, wie unstrukturiert die Pascal-Unit wirklich ist. Es ist gar nicht immer so eindeutig zu erkennen, wo eine Anweisung zu Ende ist. Das Tool ist ja kein Compiler und soll gar nicht wissen, was jedes Wort bedeutet. Es muss sich daher allein an der Struktur des Textes orientieren. "virtual;" hinter einer Prozedur-Deklaration gehört noch zu ihr. "end;" aber nicht. "Quatsch ;" würde mit zur Prozedur gehören (auch wenn es natürlich kein Pascal-Schlüsselwort ist, könnte aber vielleicht ja in 2 Jahren eins werden ;-) ) "Quatsch!" würde wohl irgendwie zur Klassendeklaration gehören. Zusätzlich können überall Leerzeichen, Kommentare und Zeichenumbrüche dazwischen stehen. Manche Anweisungen müssen mit ";" abgeschlossen werden, andere nicht, weitere werden trotz ";" fortgesetzt (wie bei "virtual") Ich bin auf einem guten Weg, denke ich, aber es war kein leichter. :-) PS: Kennt jemand sich mit den Tool-Api´s aus im Sinne Refactoring und Code-Formatierung? |
AW: Interface-Unterstützung
Zitat:
Ja, du machst keinen Compiler. Aber die Analyse sollte auf dem gleichen Weg passieren, also mit einem Parser. Sonst wird der Weg nie zu Ende sein. Ständig kommt dann irgendwelcher "Quatsch" daher an den du nicht gedacht hast. Pascal ist schließlich auch eine formatfreie Sprache. Es gibt Parser. Hier in meiner Firma wird ein solcher auch verwendet um aus interfaces Mock-Objekte zu erzeugen. Auskennen tue ich mich da aber nicht, habe nur einmal was daran geändert. |
AW: Interface-Unterstützung
Zitat:
Denn strukturiert ist das ganze schon eindeutig, nur wenn du mal z.B. in den genannten Parser hineinschaust, siehst du auch wie viele Fälle da eigentlich behandelt werden müssen... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:32 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