简体   繁体   中英

StackTrace.GetFrame throws NullReferenceException in Release build but works in Debug build

I wrote a class which is intended to provide robust logging messages. One of the features I want to include is to include the class and method from which a call to generate a log message originated.

The problem I'm having is that StackTrace.GetFrame behaves inconsistently between debug and release builds. As far as I can tell, it behaves as expected when I execute programs from VS in debug. When I execute a release build deliverable, StackTrace.GetFrame throws a NullReferenceException.

Here's a simplified example of my code:

using Logging;

namespace MyApp
{
    class Program
    {
        public static void Main(string[] args)
        {
            Logger Log = new Log(Level.INFO);
            Log.Info(@"Hello, world!");
        }
    }
}

namespace Logging
{
    class Logger
    {
        //Assume a constructor

        public void Info(string message)
        {
            //We will need to go 3 method calls back from StandardEntry()
            //to get the name of the method which called Log.Info
            StandardEntry(text, Level.INFO, 3);
        }

        //This method is called by Logger.Info, Logger.Error, etc
        private void StandardEntry(string message, Level entryLevel, int frameCount)
        {
            if (entryLevel >= this.level)
            {
               string message = $"[{CallingMethod(frameCount)}] {<entryLevel.ToString()>} {message}\r\n";
               File.AppendText(this.LogPath, message);
            }
        }

        private string CallingMethod()
        {
            string retVal;
            StackTrace st = new StackTrace();
            StackFrame sf = st.GetFrame(frameCount);
            MethodBase callingMethod = sf.GetMethod();
            return $"{callingMethod.ReflectedType.Name}.{callingMethod.Name}";
        }
    }
}

I've tried playing around with the value I'm passing in for frameCount, but a lower number returns a method call that is still within the Logger class. I need the method that actually called Log.Info

When running a release deliverable, Log.Info() in Program.Main throws a NullReferenceException, which leads me to believe that it's trying to access a stack frame index that is beyond the scope of the invoked executable.

When I debug in Visual Studio, there is no exception and CallingMethod() returns the expected expression.

看来CallerMemberNameAttribute确实是您真正需要的。

In release builds, one of the optimizations the JIT compiler performs is inlining methods, ie inserting the code of a called method directly into the method calling it. This means that some methods may simply disappear from the stack trace you're seeing.

What you can do instead is add parameters to the Info method together with the caller information attributes which are made for scenarios like this. The C# compiler will automatically fill in the information for those parameters at compile time, so they're not affected by runtime optimizations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM