Is It possibile (from inside the sub or function called ) retrieve the name of object.method or other sub or function that Is calling a sub or function ?
Example :
I have subA , subB, cmdButtonC
Inside subB i call subA
Insider cmdButtonC.click i call subA
From inside the code of subA i would like read if subA Is called by subB or by cmdButtonC.click event
While it is possible to inspect the stack and thus the calling chain, an arguably cleaner approach would be to pass everything the called method needs in a parameter. In whichever way the identity of the caller might be relevant there is a way to capture that information in an additional parameter. Chances are this would also be more efficient.
Omg, that would be a pain to manage. You’d have to remember to do that for every method and remove the items when you returned from the methods. The stack does that for you.
Depends on what you are doing. When a method must do different things depending on the who is the caller, this usually means that some information is needed that caller could have provided but didn’t. In that case it is much cleaner if it simply did provide this missing info.
Now of course there are situations when you really need to know the caller, like when you are compiling a statistics about which method is calling which other method, but these situation should be rare I think.
Take a closer look at the stack, as @Greg_O already recommended. This is probably the easiest method.
#Pragma BreakOnExceptions False
Try
Var WhoIsCallingMe As New RuntimeException("Information about the caller", 999)
Raise WhoIsCallingMe
Catch e As RuntimeException
Var stack() As String = e.Stack()
MessageBox stack(1)
End Try
#Pragma BreakOnExceptions True
“MessageBox stack(0)” replaced with “MessageBox stack(1)”
Updated after Gregs Note regarding current Method. Thank you Greg
I’m not following what this is or how it’s a problem. Michael wasn’t suggesting building a copy of the stack.
subA(true) to indicate it came from a user action like button click and subA(false) to indicate it came from within code like subB is much simpler and cleaner.
As I recall, isn’t catching and raising exceptions a performance hit?
This is what I do when I need to figure it out - I just add optional callerID as String to the parameter of the method and use System.DebugLog(“Called from :” + callerID) to add it to the log.
I add the CurrentMethodName to the whatever’s calling the method.
It’s a bit of work, but it won’t slow things down, and you can view the log as it happens.
Its a very usual design, specially for event like calls, passing the “sender”. Usually a class that fired such event (i.e. called the method) so you just know the origin, and even access it, but depending on the design could be any path tracking, as a enum for example.
In the OP case it could be as simple as
Public Enum CallOrigin
ButtonPressed
DirectCall
End Enum
Public Sub FinalMethod(origin As CallOrigin = CallOrigin.DirectCall)
If origin = CallOrigin.ButtonPressed Then
// was the button
Else
// Direct Call
End
End Sub
In every method or event handler of my larger apps I have a line of code like:
if globalVariableTraceMyCode then LogTransaction CurrentMethodName + " "+ myParams
globalVariableTraceMyCode is set to true while debugging. You can remove this stuff later once it’s all sorted.
LogTransaction is a logging module that provides a sequential event number and timestamp, writes to a text file and flushes that to disk, so it’s there even if the app crashes. Quite helpful if you need to work out exactly what happened in what order.
ok but the most interesting question would be who calls a sub or a function, the method is mostly called by the object to which it belongs..
now, it seems heavy to me to have to call a function that logs what I’m doing to which to pass both the object that calls it and the method that calls it, doing so I have not automated anything and it is useless to talk about object-oriented programming paradigms if I cannot intercept via code who calls what …
the code to generate the logs must be minimal and not full of parameters to pass to it, otherwise it is a nuisance
Public Sub WhoIsCallingMe()
#Pragma BreakOnExceptions False
Try
Var WhoIsCallingMe As New RuntimeException("Information about the caller", 999)
Raise WhoIsCallingMe
Catch e As RuntimeException
Var stack() As String = e.Stack()
System.DebugLog stack(1).Replace("%%", " in ")
End Try
#Pragma BreakOnExceptions True
End Sub
Add the above to a Module and call it from where ever you need to know who’s calling
The DebugLog will show something like this:
10:12:59 : My Application.exe Launched
10:13:00 : Window1.Window1.Event_Opening in o<Window1.Window1>
: Window1.Window1.Untitled in o<Window1.Window1>
: Module1.Test_A
10:13:04 : My Application.exe Ended
As much as I think needing to know the caller means the design is suboptimal, I’d agree with Greg and Sascha that one should use the built in stack rather than tracking their own.
great, apart from noting that in your ways I assume you studied at Oxford,
if we reasoned like you we would also have to throw away the whole part of opportunity to manage introspection.
Ps. what I don’t like about generating an error and querying the stack to understand who the caller is is precisely the issue of generating an error, which I don’t think is the best for the speed of execution of the code.
That’s true if this information were needed every time a method is called.
If that’s actually the case, then I would, like @Tim_Parnell, suspect that your solution is suboptimal. There must be another, better way. But until we learn more about why your solution should look the way you want it to, we can only help suboptimally.