以下是我想要做的一个例子:
MessageBox.Show("Error line number " + CurrentLineNumber);
在上面的代码中,CurrentLineNumber
应该是此代码片段源代码中的行号。我该如何做到这一点?
以下是我想要做的一个例子:
MessageBox.Show("Error line number " + CurrentLineNumber);
在上面的代码中,CurrentLineNumber
应该是此代码片段源代码中的行号。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 + ")");
}
例如,这将显示:
位于第39行的 Boo(某个方法的位置)
还有 [CallerFilePath]
,它告诉你原始代码文件的路径。
使用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或更高版本的用户,请考虑在System.Runtime.CompilerServices命名空间中使用CallerFilePath、CallerMethodName和CallerLineNumber属性。例如:
public void TraceMessage(string message,
[CallerMemberName] string callingMethod = "",
[CallerFilePath] string callingFilePath = "",
[CallerLineNumber] int callingFileLineNumber = 0)
{
// Write out message
}
使用 CallerMemberName
和 CallerFilePath
参数时必须是 string
类型,而 CallerLineNumber
必须是 int
类型,并且必须具有默认值。在方法参数上指定这些属性指示编译器在编译时将适当的值插入调用代码中,这意味着它可以通过混淆工作。有关更多信息,请参见Caller Information。
StackFrame
示例,请确保在编译时和运行时都使用--debug
。 - bernard paulusStackFrame
在 .NET Core 中不可用。请使用 Marc Gravell 的答案。 - Jesse Chisholm= string.Empty
会抛出错误_"'callingFilePath'的默认参数值必须是编译时常量"_! - stomy""
)而不是 string.Empty
。 - akton我更喜欢一行代码:
int lineNumber = (new System.Diagnostics.StackFrame(0, true)).GetFileLineNumber();
static int LineNumber([System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0)
{
return lineNumber;
}
LineNumber()
都会得到当前行号,这比使用StackTrace的任何解决方案都更具优势,因为它应该在调试和发布两种模式下工作。MessageBox.Show("Error enter code here line number " + LineNumber());
对于需要 .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!");
}
输出:
Void Test()(FILENAME.cs:104)
注意这里!
按您喜欢的方式更改Console.WriteLine格式!
System.Diagnostics.Debug.WriteLine(String.Format("{0}({1}): {2}: {3}", fileName, lineNumber, methodName, message));
,那么你可以点击输出窗口中的那一行并跳转到源代码对应的位置。 - Jesse Chisholmtry
{
//Do something
}
catch (Exception ex)
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
Console.WriteLine("Line: " + trace.GetFrame(0).GetFileLineNumber());
}
你只询问了带有可空项目类型的行号,那么你需要使用类似这样的代码:
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 包 Walter 中,我使用了一个超酷的类 ExceptionObject。
如果你导入了 NuGet 包,你将获得一些很好的扩展方法,可以在 Exception 类上使用,以及访问 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);
}
}