如何在不使用CallerInfo属性的情况下获取CallerFilePath和CallerLineNumber?

Ray*_*ond 6 c# reflection log4net unity-container interception

对于我的log4net解决方案,我有一个使用CallerInfo属性的API包装器,例如

    public void Write(string message,
                            [CallerMemberName] string memberName = "",
                            [CallerFilePath] string filePath = "",
                            [CallerLineNumber] int lineNumber = 0)
Run Code Online (Sandbox Code Playgroud)

但是,我也使用Unity Interception,以便我可以执行前/后响应的跟踪日志记录,例如在Invoke方法中使用如下所示的ICallHandler.

public class TraceCallHandler : ICallHandler
{
...

   public IMethodReturn Invoke(IMethodInvocation input, 
                               GetNextHandlerDelegate getNext)
    {
        //---- Trace method inputs
        this.LogInfoBeforeInvoke(input);

        //---- invoking the target method
        InvokeHandlerDelegate next = getNext();
        IMethodReturn methodReturn = next(input, getNext);

        //---- invoking the target method
        this.LogInfoAfterInvoke(methodReturn.ReturnValue); 
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:上面的代码绝不是完整/正确的...但只是想告诉你我为Unity Interception做了些什么.

我的问题/挑战是这样的:当我最终调用log.Write(...)时,我想要目标的调用者信息,而不是我的TraceCallHandler信息.

例如,对于方法名称,我可以这样做:

   string methodName = input.MethodBase.Name;
Run Code Online (Sandbox Code Playgroud)

如何获取来电者的文件路径和来电者的线路号码?甚至可以通过反思来做吗?

谢谢!

stu*_*rtd 7

是的,您可以使用反射来获取这些:

var sf = new System.Diagnostics.StackTrace(1).GetFrame(0);
Console.WriteLine(" File: {0}", sf.GetFileName());
Console.WriteLine(" Line Number: {0}", sf.GetFileLineNumber());
// Note that the column number defaults to zero 
// when not initialized.
Console.WriteLine(" Column Number: {0}", sf.GetFileColumnNumber());
Run Code Online (Sandbox Code Playgroud)

但正如它在文档中清楚地说明的那样:

使用Debug构建配置,StackFrame信息将提供最多信息.默认情况下,Debug构建包括调试符号,而Release构建则不包括.调试符号包含构造StackFrame对象时使用的大部分文件,方法名称,行号和列信息.

因此,如果你想要的只是调试,那么在调试版本中启用它并注销.在Release版本中尽管它最多是无益的,最坏的是彻头彻尾的误导,因为除了上面的符号考虑因素之外,编译器会积极地内联方法并重新排序并且通常会弄乱你的东西.