How to create predictable output with a Lazy<StackFrame>
I'm working on some internal logging framework and for the sake of performance it seems a good idea to lazily get a StackFrame
. I want to use this StackFrame
to get the first method outside m开发者_运维技巧y logging framework.
My initial idea was this:
using System;
using System.Diagnostics;
using NUnit.Framework;
[TestFixture]
public class Test
{
[Test]
public void Caller()
{
NeedsToNowCaller();
}
public void NeedsToNowCaller()
{
Processor.GetName(() => new StackFrame(4));
Really();
Assert.AreEqual("Caller", Processor.stackFrame.Value.GetMethod().Name);
}
public void Really()
{
Assert.AreEqual("Caller",Processor.stackFrame.Value.GetMethod().Name);
}
}
public static class Processor
{
public static Lazy<StackFrame> stackFrame;
public static void GetName(Func<StackFrame> stackFrameProvider)
{
stackFrame = new Lazy<StackFrame>(stackFrameProvider);
}
}
But when you swap these lines:
Really();
Assert.AreEqual("Caller", Processor.stackFrame.Value.GetMethod().Name);
Results are unpredictable, since the call stack is changed. Is there anyway to get a hook to the local scope/frame through a closure, while retaining the laziness.
The only solution i can think of is stepping through the StackTrace, until i detect the first frame with a unknown method.
I really hope there's a better solution.
I don't know that this is much better, but instead of looking for an unknown method, it might be simpler to look for a different source class. This is a bit rough, but would something like this work to give you the last frame before entering the logging class without having to maintain a list of "known" method names (assuming the logging method is not a static...)?
public void DoStuff()
{
int index = 0;
StackFrame frame = new StackFrame(index++);
while (this.GetType().Name.Equals(frame.GetMethod().DeclaringType.Name))
{
frame = new StackFrame(index++);
}
//...
}
精彩评论