C#中有__LINE__ __FILE__等价物吗?

为了logging目的

__LINE__ __FILE__ 

是我在C / C ++中的朋友。 在Java获取这些信息,我不得不抛出一个exception,并抓住它。 为什么现代编程语言中这些旧的standbys被忽略了? 他们的简单有些神奇。

这是丑陋的,但你可以在C#中使用StackTrace和StackFrame类来做这样的事情:

 StackTrace st = new StackTrace(new StackFrame(true)); Console.WriteLine(" Stack trace for current level: {0}", st.ToString()); StackFrame sf = st.GetFrame(0); Console.WriteLine(" File: {0}", sf.GetFileName()); Console.WriteLine(" Method: {0}", sf.GetMethod().Name); Console.WriteLine(" Line Number: {0}", sf.GetFileLineNumber()); Console.WriteLine(" Column Number: {0}", sf.GetFileColumnNumber()); 

当然,这有一些开销。

呼叫者信息已被添加到.NET 4.5。 这将被编译,这是一个很大的改进,不得不手动检查堆栈跟踪。

 public void Log(string message, [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) { // Do logging } 

只要以这种方式调用它,编译器就会为你填写文件名和行号:

 logger.Log("Hello!"); 

最接近这一点的事实是,你可以创build一个StackTrace对象并find堆栈顶部的方法名,这样就可以接近__FUNCTION__macros的function。

 StackTrace stackTrace = new StackTrace(); StackFrame[] stackFrames = stackTrace.GetFrames(); foreach (StackFrame stackFrame in stackFrames) Console.WriteLine(stackFrame.GetMethod().Name); 

为了减less手工input这些代码的成本,以及运行时代码,你可以编写一个辅助方法:

 [Conditional("Debug")] public void LogMethodName() { Trace.WriteLine("Entering:" + new StackTrace().GetFrame(1).GetMethod().Name); } 

请注意我们如何获得第1帧,因为第0帧将是LogMethodName本身。 通过将其标记为有条件的(“debugging”),我们确保从发布版本中删除代码,这是避免运行时成本可能不需要的一种方法。

因为堆栈跟踪包含你所需要的大部分。 它不会给你的文件的名称,但它会给你的类/方法的名称。 它还包含行号。 它不被忽视是自动的。 像Java一样,你只需要抛出exception

这是一个获取行号的方法: http : //askville.amazon.com/SimilarQuestions.do?req= line- numbers-stored-stack-trace-C%2523-application-throws-exception

如果使用log4net,则可以在日志中获取行号和文件名,但是:

  • 它可以减less你的应用程序。 性能
  • 您必须将.PDB文件与您的程序集一起使用。

使用调用者信息 (在.NET 4.5中引入),可以在C#中创build__LINE____FILE__的等价物:

 static int __LINE__([System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0) { return lineNumber; } static string __FILE__([System.Runtime.CompilerServices.CallerFilePath] string fileName = "") { return fileName; } 

唯一要记住的是这些是函数而不是编译器指令。

举个例子:

 MessageBox.Show("Line " + __LINE__() + " in " + __FILE__()); 

如果你在实践中使用这个,那么我会build议不同的名字。 我使用C / C ++名称只是为了使它更清晰地返回,而像CurrentLineNumber()CurrentFileName()可能是更好的名称。

使用呼叫者信息优于任何使用StackTrace解决scheme的优点是线路和文件信息可用于debugging和发布。

已经有一些build议来实现你想要的。 使用StackTrace对象或更好的log4net。

在Java获取这些信息,我不得不抛出一个exception,并抓住它。

这不完全正确。 你也可以没有抛出exception。 看看log4j。 它甚至会logging你的方法和类的名字,而不会用包含当前方法名称的硬编码string来污染你的代码(至less我曾经在某些场合看到过)。

为什么现代编程语言中这些旧的standbys被忽略了?

Java和C#不使用(后者:过度使用)预处理器。 我认为这很好。 滥用预处理器来编写不可读的代码非常容易。 如果程序员可以滥用一些技术,他们滥用它。

只是关于performance的一个说明,这很可能是下一个东西,你脑海里浮现出来:

如果你使用StackTrace或者log4net,你总是会阅读或者听到它很慢,因为它使用了Reflection。 我正在使用log4net,我从来没有遇到日志作为性能瓶颈。 如果是这样,我可以声明性地停用(部分)日志logging,而无需更改源代码。 与删除C / C ++代码中的所有logging行相比,这是纯粹的美丽! (此外:如果性能是主要目标,我会使用C / C ++ …尽pipeJava和C#,它永远不会死。