Autor Beitrag
OlafSt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Do 13.02.20 16:54 
Hallo Freunde,

ich pack das mal hier rein, ist zwar grafische Oberfläche, aber irgendwie auch nicht ;)

Ich möchte einen selbstgebauten Serializer erstellen. Dieser soll für einige Controls auf einem Formular genau definierte Properties serialisieren und als XML später wegspeichern. Ich dachte, Attribute wären da eine prima Idee.

Also habe ich ein ganz simples Attribut erstellt:

ausblenden Delphi-Quelltext
1:
2:
3:
type
   ASHSerializerAttribute = class(TCustomAttribute)
   end;


Mit diesem Attribut statte ich nun die spezifischen Controls meines Formulars aus:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
type
  TForm1 = class(TForm)
    [ASHSerializer] CheckBox1: TCheckBox;
    [ASHSerializer] Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;


Im ButtonClick lasse ich dann serialisieren:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
var
   I: Integer;
   TC: TComponent;
begin
     for I := 0 to self.ComponentCount-1 do
     begin
          TC:=self.Components[i];
          SerializeControl(TC);
     end;
end;


Um an das Attribut zu gelangen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
procedure SerializeControl(TheClass: TObject);
var
   LContext: TRttiContext;
   LType: TRttiType;
   LAttr: TCustomAttribute;
   LP: TArray<TCustomAttribute>;
begin
     { Einen neuen Rtti-Kontext erstellen }
     LContext := TRttiContext.Create;

     { Typinformationen für den Typ TSomeType extrahieren }
     LType := LContext.GetType(TheClass.ClassInfo);
     { Nach dem benutzerdefinierten Attribut suchen und Verarbeitung ausführen }
     LP:=LType.GetAttributes();
     for LAttr in LP do
     begin
          if LAttr is ASHSerializerAttribute then
          begin
               MessageDlg('Gotcha !', mtInformation,[mbOK],0);
          end;
     end;
     { Kontext freigeben }
     LContext.Free;
end;


Compiliert alles, läuft alles. Nur kommt nie ein "Gotcha !" hoch.

Wo liegt mein Denkfehler ?

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19288
Erhaltene Danke: 1743

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 13.02.20 18:02 
Nicht die Klasseninstanz innerhalb der Eigenschaft, also die Controls, haben das Attribut, sondern die Eigenschaften CheckBox1 und Button1! Du musst also durch die PropertiesFelder des Formulars iterieren um die Attribute abzufragen.

Du kannst ja beliebige Objekte in die Eigenschaft hineinpacken und auch wieder herausnehmen. Wo sollte die Information über das Attribut also stehen? Das Objekt weiß ja gar nicht, ob es gerade in der Property steht oder nicht. Die Attribute werden beim Kompilieren verarbeitet.


Zuletzt bearbeitet von jaenicke am Mo 17.02.20 13:32, insgesamt 1-mal bearbeitet
OlafSt Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Mo 17.02.20 13:27 
Okay, das habe ich nun erfolglos versucht:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
procedure SerializeControl(TheClass: TObject);
var
   LContext: TRttiContext;
   LType: TRttiType;
   LAttr: TCustomAttribute;
   LP: TArray<TCustomAttribute>;
   LProps: TArray<TRttiProperty>;
   LProp: TRttiProperty;
begin
     { Einen neuen Rtti-Kontext erstellen }
     LContext := TRttiContext.Create;

     { Typinformationen für den Typ TSomeType extrahieren }
     LType := LContext.GetType(TheClass.ClassInfo);
     {Properties abholen}
     LProps:=LType.GetProperties();
     {Alle Properties durchlaufen}
     for LProp in LProps do
     begin
          {Irgendwann müssten wir eine CheckBox finden}
          if LProp.Name.Contains('CheckBox'then
          begin
               LP:=LProp.GetAttributes();  //Ein Breakpoint hier wird nie erreicht
               { Nach dem benutzerdefinierten Attribut suchen und Verarbeitung ausführen }
               //LP:=LType.GetAttributes();
               for LAttr in LP do
               begin
                    if LAttr is ASHSerializerAttribute then
                    begin
                         MessageDlg('Serializable CheckBox', mtInformation,[mbOK],0);
                    end;
               end;
          end;
     end;
     { Kontext freigeben }
     LContext.Free;
end;


Der Aufruf wurde umgestellt auf Serialize(Form1). Eine Checkbox wird allerdings nie gefunden und auch ohne die Contains-Abfrage erreiche ich nie die MessageBox.

Ich bin wohl zu blöd für sowas. Und das nach 25 Jahren Delphi...

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19288
Erhaltene Danke: 1743

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 17.02.20 13:34 
Entschuldigung, das war mein Fehler. :oops: Das sind ja Felder und nicht Properties.
Mit GetFields statt GetProperties sollte es also genau so gehen wie du es jetzt hast.
OlafSt Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Di 18.02.20 09:54 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Entschuldigung, das war mein Fehler. :oops: Das sind ja Felder und nicht Properties.


*kopfklatsch* Der Schlag ins Leere. Hätte ich auch selbst drauf kommen können, als ich bei "Ltype." verharrte und im CodeCompletion die GetFields-Methode sah.

Ich probiere das heute Nachmittag aus. Wäre so megacool, wenn das funktionieren würde.

Funktioniert genau so, wie ich mir das vorgestellt habe. Vielen Dank, user profile iconjaenicke für den Schubser in die richtige Richtung !

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.