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

C# 如何在不使用CallerInfo属性的情况下获取CallerFilePath和CallerLineNumber?,c#,reflection,log4net,unity-container,interception,C#,Reflection,Log4net,Unity Container,Interception,对于我的log4net解决方案,我有一个使用CallerInfo属性的API包装器,例如 public void Write(string message, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [

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

    public void Write(string message,
                            [CallerMemberName] string memberName = "",
                            [CallerFilePath] string filePath = "",
                            [CallerLineNumber] int lineNumber = 0)
但是,我也使用Unity拦截,这样我就可以对before/after响应执行跟踪日志记录,例如,在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); 
    }
}
注:上述代码并不完整/正确。。。但我只是想让你看看我在为Unity拦截做什么

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

e、 g.对于方法名称,我可以这样做:

   string methodName = input.MethodBase.Name;
如何获取呼叫者的文件路径和呼叫者的行号?甚至可以通过反射来实现吗


谢谢

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

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());
然而,正如它在中明确指出的:

StackFrame信息将在调试构建时提供最多信息 配置。默认情况下,调试生成包含调试符号,而 发布版本不会。调试符号包含文件的大部分, 构造中使用的方法名称、行号和列信息 堆栈帧对象


因此,如果您只想进行调试,那么在调试构建中启用它并注销。在发布版本中,尽管这充其量是没有帮助的,最坏的情况下是完全误导的,因为除了上面的符号考虑之外,编译器会积极地内联方法和重新排序,通常会弄乱你的东西。

我刚刚遇到了这个问题,我想我会分享我学到的东西。首先,当您在方法参数中包含[CallerFilePath]时,副作用是文件的完整路径(包括任何用户可识别的数据)将包含在.exe中。我用一种方法创建了一个简单的程序。我创建了一个exe。然后,我向测试函数添加了一个[CallerFilePath]属性。当我比较strings.exe(来自sysinternals)的结果时,具有该属性的结果有所不同,因为它包含源文件的完整路径

c:\users\<my name>\documents\visual studio 2015\Projects\TestCallerAttribute\TestCallerAttribute\Program.cs
c:\users\\documents\visual studio 2015\Projects\TestCallerAttribute\TestCallerAttribute\Program.cs
stuartd上面的回答是正确的,因为在发布版本中,您将无法从堆栈跟踪中获得所需的数据

然而,有一种解决方案可以获取强大的数据:Windows事件跟踪。来自msdn:“Windows事件跟踪(ETW)是一种高效的内核级跟踪工具,允许您将内核或应用程序定义的事件记录到日志文件中。您可以实时或从日志文件中使用这些事件,并使用它们调试应用程序或确定应用程序中出现性能问题的位置。”


这不是一个快速的解决方案。在设置活动和听众以获得您需要的出处方面有很多工作。长期回报是巨大的。

几天前你没有问过同样的问题吗?有点。我删除了那个问题,因为有人将其标记为重复,但事实并非如此。我已经知道如何获取方法名。。。我想要文件路径和行号。感谢您提供了很棒的“答案”,但我无法将其标记为答案,因为日志跟踪的整个意义在于解决生产版本中的问题:(不过,无论您使用什么方法,都会遇到同样的问题,除非您在发布版本中包含调试信息。这并不奇怪-异步堆栈跟踪无法理解。
EnhancedStackTrace.Current()
from可能值得一看。只需将其放在.csproj文件中即可避免用户可识别数据:$(SolutionDir)=