如何获取当前行号?

下面是我想做的一个例子:

MessageBox.Show("Error line number " + CurrentLineNumber);

CurrentLineNumber以上的代码中,应该是行号在源代码中的这段代码。

我该怎么做?

100521 次浏览

使用 StackFrame. GetFileLineNumber方法,例如:

private static void ReportError(string message)
{
StackFrame callStack = new StackFrame(1, true);
MessageBox.Show("Error: " + message + ", File: " + callStack.GetFileName()
+ ", Line: " + callStack.GetFileLineNumber());
}

有关更多信息,请参见 Scott Hanselman 的博客条目

[编辑: 添加以下内容]

对于那些使用。Net 4.5或更高版本,考虑系统中的 CallerFilePathCallerMethodName致电热线号码属性。运行时间。CompilerServices 命名空间。例如:

public void TraceMessage(string message,
[CallerMemberName] string callingMethod = "",
[CallerFilePath] string callingFilePath = "",
[CallerLineNumber] int callingFileLineNumber = 0)
{
// Write out message
}

CallerMemberNameCallerFilePath的参数必须是 stringCallerLineNumber的参数必须是 int,并且必须具有默认值。在方法参数上指定这些属性指示编译器在编译时在调用代码中插入适当的值,这意味着它通过模糊处理工作。有关更多信息,请参见 来电显示

如果它在 try catch 块中,请使用。

try
{
//Do something
}
catch (Exception ex)
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
Console.WriteLine("Line: " + trace.GetFrame(0).GetFileLineNumber());
}

进去。NET 4.5/C # 5,你可以通过编写一个使用新的调用者属性的实用程序方法来让编译器为你完成这项工作:

using System.Runtime.CompilerServices;


static void SomeMethodSomewhere()
{
ShowMessage("Boo");
}
...
static void ShowMessage(string message,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null)
{
MessageBox.Show(message + " at line " + lineNumber + " (" + caller + ")");
}

这将显示,例如:

Boo 在第39行

还有 [CallerFilePath],它告诉您原始代码文件的路径。

我更喜欢一句话:

int lineNumber = (new System.Diagnostics.StackFrame(0, true)).GetFileLineNumber();

对于那些需要.NET 4.0 + 方法解决方案的人:

using System;
using System.IO;
using System.Diagnostics;


public static void Log(string message) {
StackFrame stackFrame = new System.Diagnostics.StackTrace(1).GetFrame(1);
string fileName = stackFrame.GetFileName();
string methodName = stackFrame.GetMethod().ToString();
int lineNumber = stackFrame.GetFileLineNumber();


Console.WriteLine("{0}({1}:{2})\n{3}", methodName, Path.GetFileName(fileName), lineNumber, message);
}

如何致电:

void Test() {
Log("Look here!");
}

产出:

无效测试()(FILENAME.cs: 104)

看这里!

按照您的喜好更改 Console. WriteLine 格式!

在.NET 4.5中,你可以通过创建函数得到行号:

static int LineNumber([System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0)
{
return lineNumber;
}

然后,每次您调用 LineNumber(),您将有当前行。与使用 StackTrace 的任何解决方案相比,这种方法的优势在于,它可以同时在调试和发布中工作。

因此,按照最初提出的要求,它将变成:

MessageBox.Show("Error enter code here line number " + LineNumber());

这是建立在马克•格拉维尔(Marc Gravell)出色回答的基础之上的。

您只询问了行号,并且对于可为空的项目类型,然后需要使用类似于下面这样的内容

internal class Utils
{
public static int Line([CallerLineNumber] int? lineNumber =null)=>lineNumber;
}

在您的代码中,如果您希望获得一个行号,那么只需拨打

var line=Utils.Line();

如果您正在进行日志记录,并且希望在例如日志记录中记录行号,那么可以像下面这样调用该方法

public void MyMethod(int someValue)
{
switch(someValue)
{
case 1:
if(abc<xyz)
{
logger.LogInformation("case value {someValue} this line {line} was true", someValue ,Utils.Line()-2);
}
break;


case 2:
logger.LogInformation("case value {someValue} this {line} was executed",someValue,Utils.Line());
break;
caste 3:
logger.LogInformation("case value {someValue} this {line} was executed",someValue,Utils.Line());
break;
}
}

您可以使用任何其他[ CallerXXX ]方法来扩展这个模式,并且不要在任何地方使用它们,不仅仅是在方法参数中。

在 Nuget Package 沃尔特中,我使用了一个超级酷的类 ExceptionObject

如果导入 NuGet 包,Exception 类上就有一些不错的扩展方法,并且可以访问 CallStack,该 CallStack 显示调用链,包括所有被调用方法的方法参数和参数值。

它就像一个异常堆栈,只有值显示了如何使用什么值到达目的地。

public void MyMethod()
{
try
{
    

//get me all methods, signatures, parameters line numbers file names etc used as well as assembly info of all assemblies used for documentation of how the code got here
var stack= new CallStack();
foreach( var frame in StackedFrames)
{
logger.LogDebug(frame.ToString());
}
}
catch(SqlException e)
{
var ex = new ExceptionObject(e);
logger.LogException(e,"{this} exception due to {message} {server} {procedure} TSQL-line:{sqlline}\n{TSQL}"
,e.GetType().Name
,e.Message
,ex.SqlServer
,ex.SqlProcedureName
,ex.SqlLineNumber
,ex.Tsql
,ex.CallStack);
}
catch(Exception e)
{
var ex = new ExceptionObject(e);
logger.LogException(e,"{this} exception due to {message} signature: signature}\nCallStack:", e.GetType().Name,e.Message,ex.Signature,ex.CallStack);
}
}