How To Get the Name of the Current Procedure/Function in Delphi (As a String)

后端 未结 6 1270
误落风尘
误落风尘 2020-12-29 03:47

Is it possible to obtain the name of the current procedure/function as a string, within a procedure/function? I suppose there would be some \"macro\" that is expanded at com

相关标签:
6条回答
  • 2020-12-29 04:24

    Another way to achieve the effect is to enter source metadata into a special comment like

    ValidateStruct(Struct, 'Blah'); // LOCAL_FUNCTION_NAME
    

    And then run a third-party tool over your source in a pre-compile build event to find lines with "LOCAL_FUNCTION_NAME" in such a comment, and replace all string literals with the method name in which such code appears, so that e.g. the code becomes

    ValidateStruct(Struct, 'SomeProc3'); // LOCAL_FUNCTION_NAME
    

    if the code line is inside the "SomeProc3" method. It would not be difficult at all to write such a tool in Python, for example, and this text substitution done in Delphi would be easy enough too.

    Having the substitution done automatically means you never have to worry about synchronization. For example, you can use refactoring tools to change your method names, and then your string literals will be automatically updated on the next compiler pass.

    Something like a custom source pre-processor.

    I gave this question a +1, this is a situation I have had numerous times before, especially for messages for assertion failures. I know the stack trace contains the data, but having the routine name inside the assertion message makes things that little bit easier, and doing it manually creates the danger of stale messages, as the OP pointed out.

    EDIT: The JcdDebug.pas methods as highlighted in other answers appear to be far simpler than my answer, provided that debug info is present.

    0 讨论(0)
  • 2020-12-29 04:26

    I think this is a duplicate of this question: How to get current method's name in Delphi 7?

    The answer there is that to do so, you need some form of debug info in your project, and to use, for example, the JCL functions to extract information from it.

    I'll add that I haven't used the new RTTI support in D2009/2010, but it wouldn't surprise me if there was something clever you could do with it. For example, this shows you how to list all methods of a class, and each method is represented by a TRttiMethod. That descends from TRttiNamedObject which has a Name property which "specifies the name of the reflected entity". I'm sure there must be a way to get a reference to where you currently are, ie the method that you're currently in. This is all guesswork, but try giving that a go!

    0 讨论(0)
  • 2020-12-29 04:31

    I think you are doing it the wrong way round: First, check whether there is an error and only then (that is: You need the name of the caller) use some tool like JclDebug to get the name of the caller by passing the return address from the stack to it.

    Getting the procedure name is very expensive performance wise, so you only want to do it when absolutely necessary.

    0 讨论(0)
  • 2020-12-29 04:34

    No compile time macro, but if you include enough debug information you can use the callstack to find it out. See this same question.

    0 讨论(0)
  • 2020-12-29 04:35

    We are doing something similar and only rely on a convention: putting a const SMethodName holding the function name at the very beginning.
    Then all our routines follow the same template, and we use this const in Assert and other Exception raising.
    Because of the proximity of the const with the routine name, there is little chance a typo or any discrepancy would stay there for long.
    YMMV of course...

    procedure SomeProc1(const Struct: TMyStruct);
    const
      SMethodName = 'SomeProc1';
    begin
      ValidateStruct(Struct, SMethodName);
      ...
    end;
    
    ...
    
    procedure SomeProcN(const Struct: TMyStruct);
    const
      SMethodName = 'SomeProcN';
    begin
      ValidateStruct(Struct, SMethodName);
      ...
    end;
    
    0 讨论(0)
  • 2020-12-29 04:39

    I've solved similar problems through design. Your example confuses me because you seem to already be doing this.

    You wrap your validation functions once like this:

    procedure SomeValidateProc3(const Struct: TMyStruct);
      begin
        ValidateStruct(Struct, 'SomeProc3');
      end;
    

    Then instead of repeatedly calling:

    ValidateStruct(Struct, 'SomeProc3");
    

    You call:

    SomeValidateProc3(Struct);
    

    If you have a typo, the compiler will catch it:

    SoemValidateProc3(Struct);
    

    If you use a more meaningful name for your wrapper functions like "ValidateName", the code becomes more readable also.

    0 讨论(0)
提交回复
热议问题