![]() |
Delphi-Version: 5
Attribute einer Methode in Methode abfragen
Hallo Zusammen,
ich wäre froh, wenn mir jemand bei einer Verständnisfrage zu Attributen helfen könnte. Ich möchte gerne in einer eigene Klasse Methoden durch Attribute so kennzeichnen, dass sie nur bestimmte User ausführen dürfen. (habe mal wieder vergessen, die Delphi-Version umzustellen: Habe nicht Delphi 5 :-) sondern Tokyo Pro) Ich habe mir in etwa folgenden Pseudo-Code vorgestellt:
Delphi-Quellcode:
Ich weiß nun leider nicht, wie ich mit "RightOfMethod" die Attribute der gerade ausgeführten Methode abfragen kann.
TmyClass = class
[RightAttribute('Special')] procedure DoSpecialJob; end; procedure TmyClass.DoSpecialJob; begin if not CurrentUserHasRight(RightOfMethod) then raise Exception.Create('Method not allowed for user'); // eigentlicher Code der Methode end; Man könnte natürlich das Attribut weglassen und gleich in die Methode schreiben, aber eigentlich fände ich es eleganter, wenn solche Attribute/Konfigurationen im Interface-Teil stünden und nicht in der Implementation. Also, ersatzweise ging sonst in der Implementation auch
Delphi-Quellcode:
Beginne gerade, mit Attributen zu experimentieren - und vielleicht habe ich das eine oder andere noch nicht ganz verstanden. Deshalb wäre ich für jeden Hinweis dankbar. Oder im konkreten Fall auch für eine andere Lösung des Problems :wink:
procedure TmyClass.DoSpecialJob;
begin if not CurrentUserHasRight('Special') then raise Exception.Create('Method not allowed for user'); // eigentlicher Code der Methode end; Viele Grüße Harald |
AW: Attribute einer Methode in Methode abfragen
Bin auch kein Profi, was die Attribute angeht, deshalb kann ich dir leider nicht sagen, ob es über die RTTI einen "eleganten" (wenn man RTTI überhaupt als elegant bezeichnen darf) Weg gibt, aber ich befürchte, ohne zumindest den Namen der Methode nochmal explizit darin aufzuführen bzw an die
Delphi-Quellcode:
Funktion zu übergeben, wird es recht umständlich bis unmöglich.
CurrentUserHasRight
Hauptproblem dürfte sein die Adresse der aktuellen Methode zu ermitteln, um dann deren RTTI Infos abfragen zu können. Eine Möglichkeit wäre eine "Wrapper-Funktion", welche die eigentliche Methode aufruft und vorher den Check ausführt (wird allerdings schon wieder sehr umständlich, wenn die Zielmethoden unterschiedliche Parameter und Rückgabewerte besitzen). Alternativ könntest du per inline Assembly den aktuellen
Delphi-Quellcode:
ermitteln und gegen die VTable der Objektinstanz abgleichen (um durch unterschiedliche Anzahl von Parametern bedingte Varianz zu kompensieren). Aber auch das ist ziemlich hacky und zudem nicht für 64-Bit möglich.
EIP
Edit: Noch ein paar andere Gedanken und Methoden dazu hier: ![]() ![]() |
AW: Attribute einer Methode in Methode abfragen
Vielen Dank für die Ideen und das Mitdenken. Hmmm, so ganz verstehe ich die Attribute noch nicht wirklich. Habe in einem anderen Thread (
![]() Von Uwe Raabe: ![]() und der verweist hier auf eine Info vom der Emarcadero-Hilfe ![]() Wo in Datasnap scheinbar genau sowas gemacht wird, was ich im Sinn hatte:
Delphi-Quellcode:
Doch wenn ich das richtig verstehe, hilft mir das nur, wenn ich eine Methode habe, aus der heraus
TServerMethods1 = class(TComponent)
public [TRoleAuth('admin')] function EchoString(Value: string): string; function ReverseString(Value: string): string; end; TServerMethods1.EchoString(Value: string): string; aufgerufen wird. Denn in dieser Methode - also von außerhalb TServerMethods1 und außerhalb von EchoString kann man über RTTI abfragen, welche Attribute zu TServerMethod1.EchoString gehören. Und dann kann man entscheiden lassen, ob der Aufruf stattfinden soll, oder eben nicht. Wenn man aber schon in der Methode TServerMethod1.EchoString drin ist, mag wohl wirklich nur der Weg über die Adresse gangbar sein - und das ist ja viel komplizierter, als wenn ich tatsächlich gleich meine Rechte/Rollen in der Implementation der Methode abfrage. Damit bringen mir in diesem Fall wohl die Attribute nichts. Aber vielleicht versteh ich ja das Ganze nicht wirklich und jemand kann noch etwas Licht hineinbringen? Für jeden Hinweis dankbar Harald |
AW: Attribute einer Methode in Methode abfragen
Ich hatte genau den gleichen Gedanken in vor längerer Zeit auch [1]. Auch hier hatte ich die Idee das mit Attributen festzulegen.
Letzten Endes sind wir damit echt nicht glücklich geworden. Nicht nur hat das im eigentlichen Quelltext nichts zu suchen: Klasse X kümmert sich um eine bestimmte Aufgabe, gut ist. Welcher Benutzer zu welcher Uhrzeit bei welcher Mondkonstellation was aufrufen darf sind echt ![]() Vor allem schmälert das die Wiederverwendbarkeit - Vielleicht kannst du genau die gleiche Klasse in einer anderen Anwendung gebrauchen, aber entweder gibt es hier keins oder ein völlig anderes Rechtesystem. Wir haben das so umgesetzt dass die ganze Rechte-Geschichte völlig simpel ist: Jede Aktion hat eine String-ID, und zu diesem String lässt sich nachschlagen welcher "Benutzerleven" das aufrufen darf. Darum kümmert sich derjenige der die Methode aufruft, in der Regel ist das ein Bestandteil der Oberfläche. Ganz vereinfacht:
Delphi-Quellcode:
Unit Permissions.IDs;
interface const SPECIAL_JOB = 'SPECIAL_JOB';
Delphi-Quellcode:
specialJobButton.Enabled := rightsManager.canInvoke(currentUser, SPECIAL_JOB);
Möchtest du die Rechte-Validierung trotzdem direkt in die Klasse selbst packen hier ein paar Gedanken: Namen der aktuellen Methode bestimmen Die Sache hat sicher noch einen Haken, aber mit einem TVirtualMethodInterceptor aus System.Rtti könnte man das machen:
Delphi-Quellcode:
uses
System.SysUtils, System.Rtti; type TMyObject = class private var interceptor: TVirtualMethodInterceptor; private procedure handleBefore( Instance: TObject; Method: TRttiMethod; const Args: TArray<TValue>; out DoInvoke: Boolean; out Result: TValue ); procedure handleAfter( Instance: TObject; Method: TRttiMethod; const Args: TArray<TValue>; var Result: TValue ); protected var currentMethodName: String; public constructor Create(); destructor Destroy(); override; procedure IKnowMyName(); virtual; procedure IDoNotKnowMyName(); end; constructor TMyObject.Create(); begin inherited Create(); interceptor := TVirtualMethodInterceptor.Create( ClassType() ); interceptor.OnBefore := handleBefore; interceptor.OnAfter := handleAfter; interceptor.Proxify(self); end; destructor TMyObject.Destroy(); begin if Assigned(interceptor) then begin interceptor.Unproxify(self); interceptor.Destroy(); end; inherited Destroy(); end; procedure TMyObject.handleBefore( Instance: TObject; Method: TRttiMethod; const Args: TArray<TValue>; out DoInvoke: Boolean; out Result: TValue ); begin DoInvoke := True; currentMethodName := Method.Name; end; procedure TMyObject.handleAfter( Instance: TObject; Method: TRttiMethod; const Args: TArray<TValue>; var Result: TValue ); begin currentMethodName := EmptyStr; end; procedure TMyObject.IKnowMyName(); begin WriteLn( currentMethodName.QuotedString() ); end; procedure TMyObject.IDoNotKnowMyName(); begin WriteLn( currentMethodName.QuotedString() ); end; Ebenfalls kannst du deine Methode mit dem Exception werfen verwenden: Der TVirtualMethodInterceptor hat ein OnException-Event: Wenn deine spezielle Exception geworfen wurde könnte er die schlucken und deine Methode tut einfach überhaupt nichts. Analog hat das OnBefore-Event ja auch den Parameter
Delphi-Quellcode:
. Es gibt
Method: TRttiMethod
Delphi-Quellcode:
! Hier kannst du dir alle Attribute der aktuell aufgerufenen Methode anschauen. Damit kämst du auch ans Ziel.
TRttiMethod.GetAttributes()
Nur wie gesagt, ich persönlich würde es so nicht mehr machen. So etwas gehört nicht in die eigentliche Klasse, das "verschmutzt" nur den eigentlichen Code. [1] ![]() |
AW: Attribute einer Methode in Methode abfragen
Vielen Dank für Eure Antworten und Gedanken! Ich bin wieder einmal beeindruckt, wie sehr ich von Euren Ideen und Erfahrungen hier in der DP profitieren kann.
Gerade die Frage, ob's meine Idee (die ja nicht so neu zu sein scheint) wirklich bringt, oder es nicht bessere Wege zu diesem Ziel gibt, ist mir wirklich wertvoll - vor allem, da sie ja aus Euren eigenen Erfahrungen heraus kommt. Also, ich überlege mir das Ganze nochmal, ob an dieser meiner Stelle Attribute wirklich das Mittel der Wahl sind. :wink: Viele Grüße Harald |
AW: Attribute einer Methode in Methode abfragen
thread schon etwas älter, aber ich häng mich hier mal mit einem follow-up dran.
habe zurzeit mal mit dem TVirtualMethodInterceptor experimentiert, was auch sehr gut klappt. Allerdings habe ich mit groben speicherlöchern zu tun, falls ich zum bleistift die RTTI-Attribute einer methode abfragen möchte um die dann zu intercepten:
Delphi-Quellcode:
Ist das normal? (abgesehen davon dass Lecks nicht "normal" sein sollten), kann ich das umgehen?
Procedure Dopassword(Instance: Tobject; Method: Trttimethod;
Const Args: TArray<TValue>; Out DoInvoke: Boolean; Out Result: TValue); Var Pw: String; attr:tcustomattribute; //Attributes: Tarray<Tcustomattribute>; Begin if True then Doinvoke := True; Begin attributes:= Method.GetAttributes Do; //<<<< produziert bei mir ein speicherleck, auch wenn ich erst das getattribute einer (lokalen)tarray-variable zuweise //For {Var //inline ab 10.1} Attr In Attributes Do //If Attr Is Passwordprotectedattribute //Then //do some checks>> einfach mal so eingefügt als beispiel: //Begin //Writeln('change password protected.'); //Readln(Pw); //If Pw <> 'login' //Then //Doinvoke := False; //End; End; //Setlength(Attributes, 0); End; |
AW: Attribute einer Methode in Methode abfragen
Ich kann das nicht nachvollziehen. Hast du ein funktionsfähiges Testprogramm?
Ich bekomme hier keine Speicherlecks:
Delphi-Quellcode:
// JCL_DEBUG_EXPERT_GENERATEJDBG OFF
// JCL_DEBUG_EXPERT_INSERTJDBG OFF program AtrtibTestProject; {$APPTYPE CONSOLE} {$R *.res} uses FastMM4, System.SysUtils, System.Rtti; type MyAttribute = class(TCustomAttribute); TMyObject = class(TObject) public [MyAttribute] procedure test(); virtual; end; procedure p(); var interceptor: TVirtualMethodInterceptor; myObject: TMyObject; begin interceptor := nil; myObject := nil; try myObject := TMyObject.Create(); interceptor := TVirtualMethodInterceptor.Create( myObject.ClassType() ); interceptor.OnBefore := procedure( instance: TObject; method: TRttiMethod; const args: TArray<TValue>; out doInvoke: Boolean; out result: TValue ) var attributes: TArray<TCustomAttribute>; begin attributes := method.GetAttributes(); WriteLn('We found ', Length(attributes), ' attributes'); end; interceptor.Proxify(myObject); myObject.test(); finally if Assigned(interceptor) then begin interceptor.Unproxify(myObject); interceptor.Destroy(); end; myObject.Free(); end; end; { TMyObject } procedure TMyObject.test(); begin WriteLn('Hello World'); end; begin ReportMemoryLeaksOnShutdown := True; try p(); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; readln; end. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:10 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