![]() |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Zum beispiel sowas:
Delphi-Quellcode:
Passend dafür gibts einen Serializer der auf der neuen RTTI aufbaut und wenn ich eine Liste habe, weiß ich durch das Attribute, wie der Knoten in der XML heißt und welche Klasse ich dafür erzeugen muss.
type
ListAttribute = class(TCustomAttribute) private FTagName: String; FClass: TClass; public constructor Create(const ATagName: String; AClassType: TClass); end; type TMyClass = class [ ListAttribute('SubPositions', TPositionInformation) ] property SubPositions : TObjectList<TPositionInformation> read FSubPositions write FSubPositions; [ ListAttribute('DatabaseVersions', TDatabaseVersion) ] property DatabaseVersions : TObjectList<TDatabaseVersion> read FDatabaseVersions write FDatabaseVersions; [ ListAttribute('ProductionUnits', TProductionUnit) ] property ProductionUnits : TObjectList<TProductionUnit> read FProductionUnits write FProductionUnits; [ ListAttribute('Segments', TPositionSegment) ] property Segments : TObjectList<TPositionSegment> read fSegments write FSegments; end; |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Zitat:
@Luckie: Wie scheinbar auch andere, handhabe ich das Mapping von Datenbank-Tabellen auf Objekte via Attribute. Beispiel:
Delphi-Quellcode:
So könnte das ganze aussehen. Du brauchst somit quasi nur eine Load-Methode schreiben, die via (der neuen) RTTI die abgeleitete Klasse TBlub analysiert und dann via PrimaryKey entsprechend lädt. Ist halt eine stark simplifizierte Version, aber ich denke, dass es schon aussagekräftig genug ist, bzw. das will ich mal hoffen ;)
// Tablle Blub:
// Spalte1 // Spalte2 // Spalte3 TModel = class abstract public // Diese Methode analysiert die Klasse und lädt aus der zugewiesenen // Tabelle den nötigen Datensatz procedure Load(const PrimaryKey: Integer); virtual; end; // Dazu gehörige Klasse [TTableAttribute('Blub')] // Zuweisung einer Tabelle TBlubModel = class(TModel) private [TTableColumnAttribute('Spalte1')] FValue1: String; [TTableColumnAttribute('Spalte1')] FValue2: Integer; [TTableColumnAttribute('Spalte1')] FXyz: Variant; end; -- Edit: Alternativ könnte man auch einen "Loader" verwenden -- bin in Sache Patterns bzgl sowas leider nicht all zu fit. Hier mal mein Gedankengang:
Delphi-Quellcode:
Für etwaige Fehler wird nicht gehaftet :stupid: habe gerade alles nur schnell aus dem Kopf runtergeschrieben, ohne es zu testen.
// Es liegt hier selbige Tabelle, wie oben beschrieben, zugrunde!
// Basis-Model-Klasse TModel = class abstract end; TModelClass = class of TModel; // Konkretes Model TBlubModel = class(TModel) private [TTableColumnAttribute('Spalte1')] FValue1: String; [TTableColumnAttribute('Spalte1')] FValue2: Integer; [TTableColumnAttribute('Spalte1')] FXyz: Variant; end; // Loader TBaseModelFactory = class private procedure AnalyseModel(Model: TModelClass); public function LoadByPk(Model: TModelClass; PrimaryKey: Integer): TModel; function LoadByAttributes(Model: TModelClass; Attributes: TArray<TModelAttribute>): TArray<Model>; function LoadbyWhereClause(Model: TModelClass; WhereClause: String): TArray<TModel>; end; // Nutzung: var Model : TBlubModel; Models : TArray<TBlubModel>; begin // Laden, über die Angabe des PK. Durch Angabe der klasse TBlubModel ist klar, // auf welche Tabelle zugegriffen werden muss. Model := TBaseModelFactory.LoadByPk(TBlubModel, 10); // Laden via "Filter", d.h. über Angabe von Attributen, die dann entsprechend // zu einer Where-Clause zusammengebaut werden. // WICHTIG: Die Attribute sind hier nicht in korrekter Delphi-Syntax angegeben // sondern entsprechend Pseudocode. Models := TBaseModelFactory.LoadbyAttributes(TBlubModel, ['Spalte1' = 10, 'Spalte2' = 'DP']); // ... und dann noch via selbst modelliertem Where-Clause. Models := TBaseModelFactory.LoadByWhereClause(TBlubModel, 'Spalte1 > 15 AND Spalte2 LIKE "%dp%"'); |
AW: Rätselhaftes Konstrukt in Unit Dialogs
IIRC macht Microsoft das ähnlich, wenn man z.B. in VS ein Dataset zu einer bestehenden Tabelle erstellen lässt.
|
AW: Rätselhaftes Konstrukt in Unit Dialogs
Delphi-Quellcode:
Wobei man hier uch wieder von doppelten Informationen reden könnte.
type
TMyClass = class [ ListAttribute('SubPositions', TPositionInformation) ] property SubPositions : TObjectList<TPositionInformation> read FSubPositions write FSubPositions; [ ListAttribute('DatabaseVersions', TDatabaseVersion) ] property DatabaseVersions : TObjectList<TDatabaseVersion> read FDatabaseVersions write FDatabaseVersions; [ ListAttribute('ProductionUnits', TProductionUnit) ] property ProductionUnits : TObjectList<TProductionUnit> read FProductionUnits write FProductionUnits; [ ListAttribute('Segments', TPositionSegment) ] property Segments : TObjectList<TPositionSegment> read fSegments write FSegments; end; TagName entpsricht ja dem Property-Namen, so daß man diesen Namen doch auch direkt verwenden könnte? OK, an die Klasse in dem Generic ranzukommen ist nicht so einfach, aber Möglich wäre es bestimmt auch. :stupid: |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Diese Attribute sind insbesondere spannend, wenn man sich aus der DB-Struktur komplette Quellcodes erzeugen lässt. Dann fügt man die Attribute hinzu, um später dynamisch auf allen erzeugten Klassen zugreifen zu können, ohne dass man diese alle untereinander verlinken muss.
Delphi-Quellcode:
Später kann man im Code diese Klassen alle wieder auffinden und nutzen:
type
/// <summary> /// Definitionen für das DB-Schema [inject] /// </summary> [DefineSchema('inject', '{12543F95-68E1-4F42-BA5D-479AFBBA12E1}')] TSchemaInject = class(TSchemaDefinition) public type /// <summary> /// Definitionen für die DB-SProc [inject].[Base_Login_Write] /// </summary> [DefineStoredProc(TSchemaInject, 'Base_Login_Write')] TSProcBase_Login_Write = class(TStoredProcDefinition) public ...
Delphi-Quellcode:
Aus meiner Sicht eine der besten Neuerungen in der Delphi-Language seit langer Zeit (zusammen mit den Generics)
Ctx := TRttiContext.Create;
try for Typ in Ctx.GetTypes do begin if Typ.TypeKind <> tkClass then Continue; // load schemata if not Typ.AsInstance.MetaclassType.InheritsFrom(TSchemaDefinition) then Continue; for Attr in Typ.GetAttributes do begin if not (Attr is DefineSchemaAttribute) then Continue; FKnownSchemata.Add(TSchemaDefinitionClass(Typ.AsInstance.MetaclassType)); Break; end; end; finally Ctx.Free; end; ...:cat:... |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Zitat:
|
AW: Rätselhaftes Konstrukt in Unit Dialogs
Zitat:
|
AW: Rätselhaftes Konstrukt in Unit Dialogs
Zitat:
Oder ist das bei XE2 eventuell ergänzt worden, dass so etwas wie @Scope ElementType.FIELD auch in Delphi geht: ![]() |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Überall?
Ich kenn viele Stellen, wo ich Kommentare machen kann, aber keine Attribute. Das geht immer nur vor irgendwelchen Deklarationen, wozu es eine RTTI gibt und scheinbar auch bei Variablen und Prozeduren. Auch wenn ich jetzt nicht wüßte, wie man an deren RTTI rankommt, bzw. daß sie überhaupt eine haben. Aber da die neue RTTI rießig ist und dort jeder mögliche Scheiß drinsteht, könnte ich auch glauben, daß sich dazu auch 'ne RTTI finden ließe. :wall: |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Zitat:
Hier ist eine Stackoverflow Frage und eine Aufstellung möglicher Einsatzorte: ![]() Genannt werden: Enums Function type Procedure type Event type (closure, procedure of object) Aliased type Record type Class type Record type that's internal to a class Record field Record method Class instance field Class class field (class var) Class method Global variable Global function Local variable Doch RTTI ist ja schon einen Schritt zu spät. Was ich meinte bezieht sich auf den Zeitpunkt des Compilierens, bevor RTTI erzeugt wird. Man kann in Delphi nicht angeben, dass ein selbst definiertes Attribut ausschliesslich an bestimmten Quelltextelementen wie Properties erlaubt ist - so dass Anwender des Attributes beim Versuch, es z.B. vor einer Klassendefinition oder einem Parameter zu verwenden, einen Compilerfehler erhält. Der Zweck ist offensichtlich, falsche Verwendung eines Attributes zu verhindern. In Delphi kann man erst zur Laufzeit, per RTTI, erkennen ob ein Attribut auch da steht, wo es bestimmungsgemäß hingehört. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:27 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