用于记录目的
__LINE__
__FILE__
是我在C / C ++中的朋友。在Java中获取该信息,我不得不抛出异常并抓住它。为什么在现代编程语言中忽略了这些旧的备用语言?他们的朴素有一些神奇的东西。
答案 0 :(得分:73)
Caller Information已添加到.NET 4.5中。这将被编译,这是一个必须手动检查堆栈跟踪的重大改进。
public void Log(string message,
[CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0)
{
// Do logging
}
只需以这种方式调用它,编译器就会为你填写文件名和行号:
logger.Log("Hello!");
答案 1 :(得分:26)
这很丑陋,但您可以使用StackTrace和StackFrame类在C#中执行以下操作:
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());
当然,这会带来一些开销。
答案 2 :(得分:11)
最接近这一点的是你可以创建一个StackTrace
对象并在堆栈顶部找出方法的名称,这样你就可以接近{{1 }。宏。
__FUNCTION__
为了降低手动输入的成本,以及运行时代码,您可以编写辅助方法:
StackTrace stackTrace = new StackTrace();
StackFrame[] stackFrames = stackTrace.GetFrames();
foreach (StackFrame stackFrame in stackFrames)
Console.WriteLine(stackFrame.GetMethod().Name);
注意我们如何得到第1帧,因为第0帧本身就是[Conditional("Debug")]
public void LogMethodName()
{
Trace.WriteLine("Entering:" + new StackTrace().GetFrame(1).GetMethod().Name);
}
。通过将其标记为条件(“调试”),我们确保从发布版本中删除代码,这是避免可能不需要的运行时成本的一种方法。
答案 3 :(得分:6)
使用Caller Information(在.NET 4.5中引入),您可以在C#中创建等效的__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__());
如果你在实践中使用它,那么我会建议不同的名字。我使用C / C ++名称只是为了让它更清楚地返回它们,而像CurrentLineNumber()
和CurrentFileName()
之类的东西可能是更好的名字。
使用Caller Information而不是使用StackTrace
的任何解决方案的优势在于,行和文件信息可用于调试和发布。
答案 4 :(得分:1)
因为堆栈跟踪包含您需要的大部分内容。它不会给你文件的名称,但它会给你类/方法名称。它还包含行号。它不是被忽视它是自动的。你只需像在Java中那样抛出异常
答案 5 :(得分:1)
如果您使用log4net,则可以在日志中获取行号和文件名,但是:
答案 6 :(得分:0)
已经有一些建议可以达到你想要的效果。使用StackTrace对象或更好的log4net。
在Java中获取该信息我不得不抛出异常并抓住它。
这不是真的。你可以拥有它而不会抛出异常。看看log4j。它甚至会记录您的方法和类名,而不会使用包含当前方法名称的硬编码字符串来污染您的代码(至少我在某些情况下已经看到过这种情况)。
为什么现代编程语言中忽略了这些旧的备用语言?
Java和C#没有使用(在后者:过度使用)预处理器。我觉得这很好。滥用预处理器来制作不可读的代码非常容易。如果程序员可以滥用某些技术......他们会滥用它。
只是关于性能的一个注释,这很可能是下一件事,它会出现在你脑海中:
如果您使用StackTrace或log4net,您将始终会读取或听到它很慢,因为它使用Reflection。我正在使用log4net,我从来没有遇到过记录作为性能瓶颈。如果是这样,我可以声明性地停用(部分)日志记录 - 而无需更改源代码。与删除C / C ++代码中的所有日志行相比,这是纯粹的美! (另外:如果性能是主要目标,我会使用C / C ++ ......尽管有Java和C#,但它永远不会消亡。)
答案 7 :(得分:0)
多年来使用FILE和LINE宏登录C / C ++,我真的很想在C#中使用类似的解决方案。这是我的解决方案。我更喜欢@fostandy建议创建许多具有不同数量参数的重载。这似乎不那么麻烦,并且不限制格式化参数的数量。您只需要在每次Log.Msg()调用开始时接受F.L()参数的添加即可。
using System;
using System.Runtime.CompilerServices;
namespace LogFileLine
{
public static class F
{
// This method returns the callers filename and line number
public static string L([CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
{
// Remove path leaving only filename
while (file.IndexOf("\\") >= 0)
file = file.Substring(file.IndexOf("\\")+1);
return String.Format("{0} {1}:", file, line);
}
}
public static class Log
{
// Log a formatted message. Filename and line number of location of call
// to Msg method is automatically appended to start of formatted message.
// Must be called with this syntax:
// Log.Msg(F.L(), "Format using {0} {1} etc", ...);
public static void Msg(string fileLine, string format, params object[] parms)
{
string message = String.Format(format, parms);
Console.WriteLine("{0} {1}", fileLine, message);
}
}
class Program
{
static void Main(string[] args)
{
int six = 6;
string nine = "nine";
string dog = "dog";
string cat = "cats";
Log.Msg(F.L(), "The {0} chased the {1} {2}", dog, 5, cat);
Log.Msg(F.L(), "Message with no parameters");
Log.Msg(F.L(), "Message with 8 parameters {0} {1} {2} {3} {4} {5} {6} {7}",
1, 2, 3, "four", 5, 6, 7, 8.0);
Log.Msg(F.L(), "This is a message with params {0} and {1}", six, nine);
}
}
}
这是上面这段代码的输出
Program.cs 41: The dog chased the 5 cats
Program.cs 43: Message with no parameters
Program.cs 45: Message with 8 parameters 1 2 3 four 5 6 7 8
Program.cs 48: This is a message with params 6 and nine