C#更快的堆栈跟踪

时间:2017-09-20 02:38:06

标签: c# performance stack-trace

我需要能够获得已被调用到某一点的所有方法的列表。不幸的是,我无法使用CallerInformation属性,因此几乎只留下了StackTrace。

我知道StackTrace对于性能不是很好,所以我希望有其他替代方案可以做到这一点而不是性能太重。我发现这篇文章(https://ayende.com/blog/3879/reducing-the-cost-of-getting-a-stack-trace)有一个如何加速堆栈跟踪的例子,但我不确定如何使用它来真正获得方法名称。这就是我到目前为止所拥有的:

void Main()
{
   var result = getTheStackTrace.Invoke();
}

private Func<object> getTheStackTrace;

public void FastStack()
{
    var stackFrameHelperType = typeof(object).Assembly.GetType("System.Diagnostics.StackFrameHelper");
    var GetStackFramesInternal = Type.GetType("System.Diagnostics.StackTrace, mscorlib").GetMethod("GetStackFramesInternal", BindingFlags.Static | BindingFlags.NonPublic);


    var method = new DynamicMethod("GetStackTraceFast", typeof(object), new Type[0], typeof(StackTrace), true);

    var generator = method.GetILGenerator();
    generator.DeclareLocal(stackFrameHelperType);
    generator.Emit(OpCodes.Ldc_I4_0);
    generator.Emit(OpCodes.Ldnull);
    generator.Emit(OpCodes.Newobj, stackFrameHelperType.GetConstructor(new[] { typeof(bool), typeof(Thread) }));
    generator.Emit(OpCodes.Stloc_0);
    generator.Emit(OpCodes.Ldloc_0);
    generator.Emit(OpCodes.Ldc_I4_0);
    generator.Emit(OpCodes.Ldnull);
    generator.Emit(OpCodes.Call, GetStackFramesInternal);
    generator.Emit(OpCodes.Ldloc_0);
    generator.Emit(OpCodes.Ret);
    getTheStackTrace = (Func<object>)method.CreateDelegate(typeof(Func<object>));
}

如何从调用getTheStackTrace.Invoke()来获取方法的名称我对如何获取信息感到有些困惑。任何帮助,将不胜感激。感谢。

1 个答案:

答案 0 :(得分:0)

我实际上在StackFrameHelper类中构建了类似于该示例所示的类似内容。除了我使用缓存/编译的表达式树来调用函数而不是IL,因为你需要调用大约5或6个方法而且一切都是内部/私有的。由于版权问题,无法发布课程,但我至少可以指出您正确的方向。您需要新建一个StackFrameHelper实例,然后调用GetStackFramesInternal,然后调用GetNumberOfFrames,然后为每个帧调用GetMethodBase,如果需要该信息,可以调用GetFileName和GetLineNumber。

除了StackFrame类上的GetStackFramesInternal之外,所有这些方法都在StackFrameHelper类上。

上面的代码只是转到GetStackFramesInternal级别,它填充了StackFrameHelper实例。