AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

RTTI Attribute verändern

Ein Thema von Neutral General · begonnen am 5. Mai 2014 · letzter Beitrag vom 7. Mai 2014
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#1

RTTI Attribute verändern

  Alt 5. Mai 2014, 17:41
Delphi-Version: XE4
Hallo,

Ist es möglich zur Laufzeit die Werte von RTTI-Attributen einer Klasse/Property/Methode zu ändern?
Auslesen ist ja kein Problem. Aber kann man da auch zur Laufzeit was ändern?
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.036 Beiträge
 
Delphi 12 Athens
 
#2

AW: RTTI Attribute verändern

  Alt 5. Mai 2014, 18:25
Eigentlich nein, denn die Typinfos sind ja fest einkompilert.

Aber man könnte den Schreibschutz von dem Speicherbreich entfernen und dann darin rumschreiben.
Windows verwaltet diesen Speicher ja als CopyOnWrite (standardmäßig aus der Datei gemappt, aber bei Veränderung wird im Hintergrund die Speicherverwaltung umgestellt)

Es ist aber nur möglich bestehende Attribute umzuschreiben, zu ersetzen oder zu entfernen.
Hinzufügen ist nicht so leicht, da es sich bei diesem AttrData um ein statisches Array handelt.
Delphi-Quellcode:
GetTypeData(TypeInfo(TDeinTyp)).AttrData // alte RTTI
TRttiType(...).TypeData.AttrData // Neue



Oder du baust dir eine Attribute-Klasse, welche sich die Daten nicht nur über die Parameter besorgt.
In den Parametern stehet dann z.B. nur die Position, wo das Attribut die Daten herholen soll und an der Stelle kannst du diese vermutlich veliebig verändern. (ich weiß jetzt allerdings nicht wann die Attribute-Instanzen genau erstellt werden und wie lange deren Lebensdauer ist)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu ( 5. Mai 2014 um 18:28 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#3

AW: RTTI Attribute verändern

  Alt 6. Mai 2014, 10:17
Hallo,

Danke schon mal für die Antwort. Hinzufügen muss ich nicht, ich will nur ein vorhandenes Attribut ändern oder ersetzen (wenn Ändern nicht geht).

Ich will das Attribut einer Property ändern:

Delphi-Quellcode:
type
  TTestAttribut = class(TCustomAttribute)
  private
    FValue: Boolean;
  public
    constructor Create(AValue: Boolean);
    property Value: Boolean read FValue write FValue;
  end;

  TTest = class
    FString: String;
  public
    [TTestAttribut(false)] property Test: String read FString write FString;
  end;
 
// ....

var rtti: TRttiContext;
    typ: TRttiType;
    Prop: TRttiProperty;
    attrData: PAttrData;
    oldProt: Cardinal;
begin
  rtti := TRttiContext.Create;
  typ := rtti.GetType(ClassType);
  Prop := typ.GetProperty(APropName);

  attrData := @prop.PropertyType.Handle^.TypeData^.AttrData;
  VirtualProtect(attrData,4096,PAGE_READWRITE,oldProt);
  inc(attrData,SizeOf(Word)); // TAttrData.Len überspringen
  PAttrEntry(attrData)^... // Dabei kommt nix sinnvolles raus.
end;
Das Problem ist dass in attrData, bzw. PAttrEntry(attrData)^ nichts sinnvolles drin steht.
Ich weiß aber auch nicht wo ich den Fehler mache :/
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.016 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#4

AW: RTTI Attribute verändern

  Alt 6. Mai 2014, 10:24
Du kannst auch die Property beim Attribut schreibbar machen und es nach dem erstem Auslesen ändern.
Dazu musst du aber dafür sorgen, dass dein TRttiContext so lange lebt, wie du diesen geänderten Wert behalten willst. Somit bleiben auch die ganzen RTTI Objekte inkl der Attribut Instanzen am Leben.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.036 Beiträge
 
Delphi 12 Athens
 
#5

AW: RTTI Attribute verändern

  Alt 6. Mai 2014, 11:39
Jede RTTI-Instanz besitzt ihre eigenen Listen.

Sobald das erste Mal in einem Context das Attribut ausgelesen wird, wird im jeweiligem GetAttributes eine eigene Instanz des Attributes erstellt.
Ja, man kann der einen Instanz einen neuen Wert zuweisen, aber Dieser gilt dann auch nur dort und andere/fremde Instanzen haben dennoch den Urspungswert.
Also eigentlich sind die Setter sinnlos. (entweder direkt die RTTI umschreiben, aber bestehende Instanzen bleiben unberührt, oder den Wert dynamisch holen)

Nach dem "nochmal" sieht man das Erzeugen der zweiten TTest1Attribute-Instanz.

Delphi-Quellcode:
type
  TTest1Attribute = class(TCustomAttribute)
  private
    FValue: Boolean;
    function GetValue: Boolean;
    procedure SetValue(AValue: Boolean);
  public
    constructor Create(AValue: Boolean);
    destructor Destroy; override;
    property Value: Boolean read GetValue write SetValue;
  end;

  TTest2Attribute = class(TCustomAttribute)
  private
    FName: string;
    function GetValue: Boolean;
  public
    constructor Create(AName: string; AValue: Boolean=False);
    property Value: Boolean read GetValue;
  private
    class var FValues: array[0..10] of Boolean; //TDictionary<string,Boolean>;
  public
    class procedure SetValue(AName: string; AValue: Boolean); // der Name wird erstmal nur einfach auf den Index umgecastet (Tipp: das TDictionary und ein Class-Constructor)
  end;

  TTest = class
  private
    FString: string;
  public
    [TTest1(False)] property Test1: string read FString write FString;
    [TTest2('2')] property Test2: string read FString write FString;
  end;

constructor TTest1Attribute.Create(AValue: Boolean);
begin
  inherited Create;
  FValue := AValue;
  ShowMessage(ClassName + ': Create');
end;

destructor TTest1Attribute.Destroy;
begin
  ShowMessage(ClassName + ': Destroy');
  inherited;
end;

function TTest1Attribute.GetValue: Boolean;
begin
  ShowMessage(ClassName + ': GetValue');
  Result := FValue;
end;

procedure TTest1Attribute.SetValue(AValue: Boolean);
begin
  ShowMessage(ClassName + ': SetValue');
  FValue := AValue;
end;

constructor TTest2Attribute.Create(AName: string; AValue: Boolean);
begin
  inherited Create;
  FName := AName;
  SetValue(AName, AValue);
end;

function TTest2Attribute.GetValue: Boolean;
begin
  Result := FValues[StrToInt(FName)];
end;

class procedure TTest2Attribute.SetValue(AName: string; AValue: Boolean);
begin
  FValues[StrToInt(AName)] := AValue;
end;
Delphi-Quellcode:
var
  rtti: TRttiContext;
  typ: TRttiType;
  prop1: TRttiInstanceProperty;
  prop2: TRttiInstanceProperty;
  attr: ^TAttrData;
  protOld: Cardinal;
  attrObj: TCustomAttribute;
begin
  ShowMessage(ClassName + ': Begin');
  rtti := TRttiContext.Create;
  typ := rtti.GetType({ClassType}TTest);
  prop1 := typ.GetProperty({APropName}'Test1') as TRttiInstanceProperty;
  prop2 := typ.GetProperty({APropName}'Test2') as TRttiInstanceProperty;

  //for attrObj in prop1.GetAttributes do
  // if attrObj is TTest1Attribute then
  // ShowMessage(attrObj.ClassName + ': ' + BoolToStr(TTest1Attribute(attrObj).Value, True)) // billig gecastet ... den Value-Property hätte man ja auch via RTTI suchen und auslesen können
  // else if attrObj is TTest2Attribute then
  // ShowMessage(attrObj.ClassName + ': ' + BoolToStr(TTest2Attribute(attrObj).Value, True))
  // else
  // ShowMessage(attrObj.ClassName);
  attrObj := prop1.GetAttributes[0]; ShowMessage(attrObj.ClassName + ': ' + BoolToStr((attrObj as TTest1Attribute).Value, True));
  attrObj := prop2.GetAttributes[0]; ShowMessage(attrObj.ClassName + ': ' + BoolToStr((attrObj as TTest2Attribute).Value, True));

  attr := @GetTypeData(prop1.Handle).AttrData; // @prop.TypeData^.AttrData; // TypeData ist Privat
  VirtualProtect(attr, 4096, PAGE_READWRITE, protOld);
  Inc(attr, SizeOf(Word)); // TAttrData.Len überspringen
  if PAttrEntry(attr).AttrCtor = nil then ; // k.A.
  VirtualProtect(attr, 4096, protOld, protOld);

  (prop1.GetAttributes[0] as TTest1Attribute).Value := True;

  TTest2Attribute.SetValue('2', True);

  attrObj := prop1.GetAttributes[0]; ShowMessage(attrObj.ClassName + ': ' + BoolToStr((attrObj as TTest1Attribute).Value, True));
  attrObj := prop2.GetAttributes[0]; ShowMessage(attrObj.ClassName + ': ' + BoolToStr((attrObj as TTest2Attribute).Value, True));

  // nochmal
  rtti := TRttiContext.Create;
  typ := rtti.GetType({ClassType}TTest);
  prop1 := typ.GetProperty({APropName}'Test1') as TRttiInstanceProperty;
  prop2 := typ.GetProperty({APropName}'Test2') as TRttiInstanceProperty;

  attrObj := prop1.GetAttributes[0]; ShowMessage(attrObj.ClassName + ': ' + BoolToStr((attrObj as TTest1Attribute).Value, True));
  attrObj := prop2.GetAttributes[0]; ShowMessage(attrObj.ClassName + ': ' + BoolToStr((attrObj as TTest2Attribute).Value, True));

  ShowMessage(ClassName + ': End');
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu ( 6. Mai 2014 um 13:52 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.016 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#6

AW: RTTI Attribute verändern

  Alt 6. Mai 2014, 12:30
Sobald das erste Mal in einem Context das Attribut ausgelesen wird, wird im jeweiligem GetAttributes eine eigene Instanz des Attributes erstellt.
Ja, man kann der einen Instanz einen neuen Wert zuweisen, aber Dieser gilt dann auch nur dort und andere/fremde Instanzen haben dennoch den Urspungswert.
Also eigentlich sind die Setter sinnlos. (entweder direkt die RTTI umschreiben, aber bestehende Instanzen bleiben unberührt, oder den Wert dynamisch holen)

Nach dem "nochmal" sieht man das Erzeugen der zweiten TTest1Attribute-Instanz.
Und genau deshalb schrieb ich:
Dazu musst du aber dafür sorgen, dass dein TRttiContext so lange lebt, wie du diesen geänderten Wert behalten willst. Somit bleiben auch die ganzen RTTI Objekte inkl der Attribut Instanzen am Leben.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.036 Beiträge
 
Delphi 12 Athens
 
#7

AW: RTTI Attribute verändern

  Alt 6. Mai 2014, 12:35
Und genau deshalb schrieb ich:
Was nur geht, wenn die lesende Stelle den selben Context verwendet, wie die Schreibende.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu ( 6. Mai 2014 um 12:43 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.016 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#8

AW: RTTI Attribute verändern

  Alt 6. Mai 2014, 13:34
Und genau deshalb schrieb ich:
Was nur geht, wenn die lesende Stelle den selben Context verwendet, wie die Schreibende.
Falsch, es gibt intern nur eine Instanz der TRttiPool Klasse, welche durch den TRttiContext record gewrappt wird.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.036 Beiträge
 
Delphi 12 Athens
 
#9

AW: RTTI Attribute verändern

  Alt 6. Mai 2014, 13:49
Sicher?

Siehe mein TestCode. (getestet in XE)
Da wird zwei mal "gleichzeitig" eine Instanz des TTest1Attribute erzeugt, nach dem "nochmal", obwohl es davon nur ein Attribut.

Es ändert sich auch nichts, selbst wenn ich nach dem "nochmal" eigene Variablen verwende und die ersten Instanzen nicht überschreibe.
TTest1Attribute ist bei der letzen Abfrage auch wieder False.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu ( 6. Mai 2014 um 14:00 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.016 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#10

AW: RTTI Attribute verändern

  Alt 6. Mai 2014, 13:59
Sicher?

Siehe mein TestCode. (getestet in XE)
Da wird zwei mal "gleichzeitig" eine Instanz des TTest1Attribute erzeugt, nach dem "nochmal", obwohl es davon nur ein Attribut.
Ja, 100% sicher, ich kenn nämlich den Rtti.pas Source inzwischen fast im Schlaf.

Garantiert wird bei dem Source, den du gepostet hast nicht mehrfach eine Attribut Instanz erzeugt. Außer du hast lokal bei dir noch vor dem "nochmal" einen rtti.Free Aufruf.
Wenn du mir nicht glaubst, dann debug doch durch das TRttiContext.Create .

Oder du liest den Artikel von Barry dazu.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie ( 6. Mai 2014 um 14:06 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:47 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz