I've got sort of a unique situation. I've been working on an open source library for sending email. In this library, I need a reliable way to get the calling method. I've done this with a StackTrace
by analyzing the StackFrame
objects inside it. This works without issue in a debug-mode project where optimizations are turned off.
The problem occurs when I switch to release mode where optimizations are turned on. The stack trace looks like this:
> FindActionName at offset 66 in file:line:column <filename unknown>:0:0 > Email at offset 296 in file:line:column <filename unknown>:0:0 > CallingEmailFromRealControllerShouldFindMailersActionName at offset 184 in file:line:column <filename unknown>:0:0 > _InvokeMethodFast at offset 0 in file:line:column <filename unknown>:0:0 > InvokeMethodFast at offset 152 in file:line:column <filename unknown>:0:0 ...
This is taken from a failing unit test. In line 3 of this trace, I should see a method called TestEmail
which is defined elsewhere, but I believe the JITter is inlining it. I've read that you can prevent inlining by making a method virtual, but this doesn't work. Does anyone know of a reliable method for preventing method inlining so your method will show up in a stack trace?
What Method Inlining Is? Basically, inlining is a way to optimize compiled source code at runtime by replacing the invocations of the most often executed methods with its bodies. Although there's compilation involved, it's not performed by the traditional javac compiler, but by the JVM itself.
Inlining is the process by which code is copied from one function (the inlinee) directly into the body of another function (the inliner). The reason for this is to save the overhead of a method call and the associated work that needs to be done when control is passed from one method to another.
No, Java does not provide inline functions it is typically done by the JVM at execution time.
You could use MethodImplAttribute
and specify MethodImplOptions.NoInlining
.
[MethodImpl(MethodImplOptions.NoInlining)] void YourMethod() { // do something }
Note that this still doesn't guarantee that you can get at the actual calling method as seen in the source code. Your method won't be inlined, but your method's caller could be inlined into its own caller, etc etc.
You could use additional parameters marked with System.Runtime.CompilerServices.CallerMemberNameAttribute
and it's siblings CallerFilePath
and CallerLineNumber
. If I understand it correctly this should get you the correct method name, no matter what's inlined an what's not. You will only get the method name however, I don't see anything to get the class name/assembly etc.
It should go without saying, but just to be sure... something like this should not be used outside of logging/diagnostics.
Proper ways to do this would probably be:
Thread.ExecutionContext
while calling the functionI realize that this probably won't be of any help to Scott after all this time, but maybe someone else can benefit from it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With