Comment Obtenir le Nom de la Fonction/Procédure en Delphi (Comme une Chaîne de caractères)
Est-il possible d'obtenir le nom de la procédure en cours/fonction comme une chaîne de caractères au sein d'une procédure/fonction? Je suppose qu'il y aurait quelques "macro" qui est développée au moment de la compilation.
Mon scénario est le suivant: j'ai beaucoup de procédures qui sont donnés un dossier et ils ont tous besoin de commencer par la vérification de la validité de l'enregistrement, et donc qu'ils passent à l'enregistrement à un "programme de validation de la procédure". Le programme de validation de la procédure (le même pour toutes les procédures) lève une exception si l'enregistrement n'est pas valide, et je veux que le message de l'exception ne comprend pas le nom du programme de validation de la procédure, mais le nom de la fonction/procédure qui a appelé le responsable de la validation de la procédure (naturellement).
Qui est, je l'ai
procedure ValidateStruct(const Struct: TMyStruct; const Sender: string);
begin
if <StructIsInvalid> then
raise Exception.Create(Sender + ': Structure is invalid.');
end;
et puis
procedure SomeProc1(const Struct: TMyStruct);
begin
ValidateStruct(Struct, 'SomeProc1');
...
end;
...
procedure SomeProcN(const Struct: TMyStruct);
begin
ValidateStruct(Struct, 'SomeProcN');
...
end;
Il serait un peu moins sujettes à l'erreur si je plutôt écrire quelque chose comme
procedure SomeProc1(const Struct: TMyStruct);
begin
ValidateStruct(Struct, {$PROCNAME});
...
end;
...
procedure SomeProcN(const Struct: TMyStruct);
begin
ValidateStruct(Struct, {$PROCNAME});
...
end;
et à chaque fois que le compilateur rencontre un {$NOMPROC}, il remplace simplement le "macro" avec le nom de la fonction/procédure comme une chaîne littérale.
Mise à jour
Le problème avec la première approche est qu'elle est sujette à erreur. Par exemple, il arrive facilement que vous vous trompez, en raison de copier-coller:
procedure SomeProc3(const Struct: TMyStruct);
begin
ValidateStruct(Struct, 'SomeProc1');
...
end;
ou des fautes de frappe:
procedure SomeProc3(const Struct: TMyStruct);
begin
ValidateStruct(Struct, 'SoemProc3');
...
end;
ou temporaire de la confusion:
procedure SomeProc3(const Struct: TMyStruct);
begin
ValidateStruct(Struct, 'SameProc3');
...
end;
- Ce serait chouette, mais autant que je sache, il n'existe pas - et j'ai fait une recherche pour quelque chose de similaire. La seule solution générique, que je sache, serait d'utiliser les informations de débogage qui est incorporé dans le fichier EXE pour obtenir le nom de la procédure, mais ce serait un grand gain de performance au moment de l'exécution. Quand j'ai besoin de quelque chose de similaire, j'ai écrit un petit programme qui allait porter mes PAS les fichiers et remplacer une certaine expression avec un peu de texte, mais pour moi, nom de fichier + le numéro de ligne est assez, je n'ai pas le nom de la procédure.
- C'est mon expérience que les fautes de frappe et de confusion ne sont pas une grosse affaire. Aussi longtemps que vos journaux d'identification par nom, il n'a pas d'importance que ce nom est. Si vous n'avez pas vraiment une fonction par son nom, grep et vous trouverez la seule occurrence du nom mal orthographié dans la fonction que vous recherchez, de toute façon.
- FWIW, il existe des outils qui le fera pour vous. Je suis familier avec CodeSite qui va ajouter de tels appels à des fonctions de journalisation à l'aide de son système.
Vous devez vous connecter pour publier un commentaire.
Nous faisons quelque chose de similaire et seulement compter sur une convention: mettre un const
SMethodName
maintenant le nom de la fonction au tout début.Puis tous nos routines de suivre le même modèle, et nous utilisons cette const en Affirmer et d'autres Exception de sensibilisation.
En raison de la proximité de la const avec le nom de routine, il y a peu de chance une faute de frappe ou de divergence voudrais y rester pour longtemps.
YMMV bien sûr...
Je pense que c'est un doublon de cette question: Comment obtenir de l'actuelle méthode de Delphi 7?
La réponse est que, pour ce faire, vous avez besoin d'une certaine forme d'informations de débogage dans votre projet, et à utiliser, par exemple, la JCL fonctions pour en extraire les informations.
Je vais ajouter que je n'ai pas utilisé le nouveau RTTI soutien dans D2009/2010, mais il ne m'étonne pas s'il y avait quelque chose d'intelligent que vous pourriez faire avec elle. Par exemple, cela vous montre comment liste de toutes les méthodes d'une classe, et chaque méthode est représentée par un TRttiMethod. Qui descend de TRttiNamedObject qui a un Nom de la propriété qui "spécifie le nom de l'reflète l'entité". Je suis sûr qu'il doit y avoir un moyen d'obtenir une référence à l'endroit où vous êtes actuellement, c'est à dire la méthode que vous vivez actuellement. C'est toutes les conjectures, mais essayez de lui donner un aller!
__FUNC__
et similaires. Le compilateur Delphi n'est pas, et nous ne pouvons pas changer la source du compilateur, de sorte que votre commentaire n'aide pas vraiment. Mais peut-être cela explique pourquoi en utilisant les informations de débogage est nécessaire.Aucun moment de la compilation, de la macro, mais si vous d'inclure suffisamment d'informations de débogage, vous pouvez utiliser la pile d'appels pour la trouver. Voir cette même question.
Une autre façon d'obtenir l'effet est à l'entrée de la source de métadonnées dans un commentaire spécial comme
Puis exécutez un outil tiers sur votre source dans un pré-compiler pour créer un événement à trouver des lignes avec "LOCAL_FUNCTION_NAME" dans un commentaire, et de le remplacer tous les littéraux de chaîne avec le nom de la méthode dans laquelle le code s'affiche, de sorte que, par exemple, le code devient
si la ligne de code à l'intérieur de la "SomeProc3" la méthode. Il ne serait pas difficile d'écrire un tel outil en Python, par exemple, et ce texte de substitution fait en Delphi serait assez facile aussi.
Avoir la substitution fait automatiquement, vous n'avez jamais à vous soucier de la synchronisation. Par exemple, vous pouvez utiliser le refactoring changer votre méthode de noms, et puis votre littéraux de chaîne sera automatiquement mis à jour sur la prochaine passe de compilateur.
Quelque chose comme une coutume source pré-processeur.
J'ai donné à cette question un +1, c'est une situation que j'ai eu de nombreuses fois avant, en particulier pour les messages de l'affirmation des échecs. Je sais que la trace de la pile contient les données, mais en ayant le nom de routine à l'intérieur de l'affirmation message rend les choses un peu plus facile, et de le faire manuellement crée le danger de vieux messages, comme l'OP souligné.
MODIFIER: Le
JcdDebug.pas
les méthodes de mise en évidence dans d'autres réponses semblent être beaucoup plus simple que ma réponse, à condition que les informations de débogage est présent.J'ai résolu des problèmes similaires à travers le design. Votre exemple me confond parce que vous semblez être déjà fait cette.
Vous enveloppez vos fonctions de validation une fois comme ceci:
Alors au lieu de réitérer l'appel:
Vous appelez le:
Si vous avez une faute de frappe, le compilateur va l'attraper:
Si vous utilisez un nom plus significatif pour votre enveloppe des fonctions comme "ValidateName", le code devient plus lisible aussi.
Je pense que vous faites le mauvais sens:
Tout d'abord, vérifier si il y a une erreur et ensuite seulement (ce qui est: Vous avez besoin du nom de l'appelant) utiliser un outil comme JclDebug pour obtenir le nom de l'appelant en passant l'adresse de retour de la pile à elle.
Obtenir le nom de la procédure est très coûteuse performance sage, de sorte que vous ne voulez le faire lorsque c'est absolument nécessaire.