using System.Diagnostics;
// Get call stack
StackTrace stackTrace = new StackTrace();
// Get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);
static void Log(object message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string fileName = "",
[CallerLineNumber] int lineNumber = 0)
{
// we'll just use a simple Console write for now
Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, memberName, message);
}
Determining the caller using the stack
static void Log(object message)
{
// frame 1, true for source info
StackFrame frame = new StackFrame(1, true);
var method = frame.GetMethod();
var fileName = frame.GetFileName();
var lineNumber = frame.GetFileLineNumber();
// we'll just use a simple Console write for now
Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, method.Name, message);
}
Comparison of the 2 approaches
Time for 1,000,000 iterations with Attributes: 196 ms
Time for 1,000,000 iterations with StackTrace: 5096 ms
/// <summary>
/// Returns the call that occurred just before the "GetCallingMethod".
/// </summary>
public static string GetCallingMethod()
{
return GetCallingMethod("GetCallingMethod");
}
/// <summary>
/// Returns the call that occurred just before the the method specified.
/// </summary>
/// <param name="MethodAfter">The named method to see what happened just before it was called. (case sensitive)</param>
/// <returns>The method name.</returns>
public static string GetCallingMethod(string MethodAfter)
{
string str = "";
try
{
StackTrace st = new StackTrace();
StackFrame[] frames = st.GetFrames();
for (int i = 0; i < st.FrameCount - 1; i++)
{
if (frames[i].GetMethod().Name.Equals(MethodAfter))
{
if (!frames[i + 1].GetMethod().Name.Equals(MethodAfter)) // ignores overloaded methods.
{
str = frames[i + 1].GetMethod().ReflectedType.FullName + "." + frames[i + 1].GetMethod().Name;
break;
}
}
}
}
catch (Exception) { ; }
return str;
}
StackFrame frame = new StackFrame(1);
frame.GetMethod().Name; //Gets the current method name
MethodBase method = frame.GetMethod();
method.DeclaringType.Name //Gets the current class name
8
private static MethodBase GetCallingMethod()
{
return new StackFrame(2, false).GetMethod();
}
private static Type GetCallingType()
{
return new StackFrame(2, false).GetMethod().DeclaringType;
}
17 回答
试试这个:
它来自Get Calling Method using Reflection [C#] .
在C#5中,您可以使用来电者信息获取该信息:
你也可以得到
[CallerFilePath]
和[CallerLineNumber]
.您可以使用来电者信息和可选参数:
该测试说明了这一点:
虽然StackTrace的工作速度非常快,但在大多数情况下都不会出现性能问题,但Caller Information的速度要快得多 . 在1000次迭代的样本中,我将其计时速度提高了40倍 .
通常,您可以使用System.Diagnostics.StackTrace类获取System.Diagnostics.StackFrame,然后使用GetMethod()方法获取System.Reflection.MethodBase对象 . 但是,这种方法有some caveats:
它表示 runtime 堆栈 - 优化可以内联一个方法,你将 not 在堆栈跟踪中看到该方法 .
它会 not 显示任何原生帧,所以如果你的方法有可能被本机方法调用,这将是 not 工作,实际上目前没有可行的方法 .
(注意:我正在扩展由Firas Assad提供的the answer . )
我们可以通过仅实例化我们实际需要的帧而不是整个堆栈来改进阿萨德先生的代码(当前接受的答案):
这可能会更好一点,但很可能它仍然必须使用完整堆栈来创建该单帧 . 此外,它仍然有Alex Lyman指出的相同警告(优化器/本机代码可能会破坏结果) . 最后,您可能需要检查以确保
new StackFrame(1)
或.GetFrame(1)
不会返回null
,因为这种可能性似乎不太可能 .看到这个相关的问题:Can you use reflection to find the name of the currently executing method?
快速回顾两种方法,速度比较是重要的部分 .
http://geekswithblogs.net/BlackRabbitCoder/archive/2013/07/25/c.net-little-wonders-getting-caller-information.aspx
Determining the caller at compile-time
Determining the caller using the stack
Comparison of the 2 approaches
从.NET 4.5开始,您可以使用Caller Information属性:
CallerFilePath - 调用该函数的源文件;
CallerLineNumber - 调用该函数的代码行;
CallerMemberName - 调用该函数的成员 .
此工具也存在于“.NET Core”和“.NET Standard”中 .
References
Microsoft - Caller Information (C#)
Microsoft - CallerFilePathAttribute Class
Microsoft - CallerLineNumberAttribute Class
Microsoft - CallerMemberNameAttribute Class
请注意,由于优化,这样做在发布代码中将是不可靠的 . 此外,以沙箱模式(网络共享)运行应用程序将不允许您抓取堆栈帧 .
考虑aspect-oriented programming(AOP),如PostSharp,它不是从您的代码中调用,而是修改您的代码,从而随时了解它的位置 .
显然这是一个迟到的答案,但如果您可以使用.NET 4.5或更高版本,我有更好的选择:
这将打印当前日期和时间,然后是"Namespace.ClassName.MethodName"并以": text"结尾 .
样本输出:
样品用途:
也许你正在寻找这样的东西:
这里有一个很棒的课程:http://www.csharp411.com/c-get-calling-method/
我使用的另一种方法是向相关方法添加参数 . 例如,使用
void Foo(string context)
而不是void Foo()
. 然后传入一些指示调用上下文的唯一字符串 .如果您只需要调用者/上下文进行开发,则可以在发货前删除
param
.看看Logging method name in .NET . 小心在 生产环境 代码中使用它 . StackFrame可能不可靠......
我们也可以使用lambda来查找调用者 .
假设您有一个由您定义的方法:
你想找到它的来电者 .
1.更改方法签名,以便我们有一个Action类型的参数(Func也可以):
3.当我们调用MethodA时,Action / Func参数必须是由调用方法生成 . 例:
4.在MethodA中,我们现在可以调用上面定义的辅助函数,并找到调用方法的MethodInfo .
例:
我想,这就足够了 .