如何找到调用当前方法的方法?
作者:互联网
登录C#时,如何得知调用当前方法的方法的名称? 我知道有关System.Reflection.MethodBase.GetCurrentMethod()
全部知识,但是我想在堆栈跟踪中比这低一级。 我已经考虑过解析堆栈跟踪,但是我希望找到一种更清晰,更明确的方式,类似于Assembly.GetCallingAssembly()
但用于方法。
#1楼
您可以使用“呼叫者信息”和可选参数:
public static string WhoseThere([CallerMemberName] string memberName = "")
{
return memberName;
}
该测试说明了这一点:
[Test]
public void Should_get_name_of_calling_method()
{
var methodName = CachingHelpers.WhoseThere();
Assert.That(methodName, Is.EqualTo("Should_get_name_of_calling_method"));
}
尽管StackTrace可以在上面快速运行,并且在大多数情况下不会成为性能问题,但呼叫者信息仍然要快得多。 在1000次迭代的示例中,我将其速度提高了40倍。
#2楼
StackFrame caller = (new System.Diagnostics.StackTrace()).GetFrame(1);
string methodName = caller.GetMethod().Name;
我认为就足够了。
#3楼
我们也可以使用lambda来查找调用者。
假设您有一个定义的方法:
public void MethodA()
{
/*
* Method code here
*/
}
而您想找到它的呼叫者。
1 。 更改方法签名,以便我们有一个类型为Action的参数(Func也可以使用):
public void MethodA(Action helperAction)
{
/*
* Method code here
*/
}
2 。 Lambda名称不是随机生成的。 规则似乎是:> <CallerMethodName> __ X,其中CallerMethodName被上一个函数替换,X是索引。
private MethodInfo GetCallingMethodInfo(string funcName)
{
return GetType().GetMethod(
funcName.Substring(1,
funcName.IndexOf(">", 1, StringComparison.Ordinal) - 1)
);
}
3 。 当我们调用MethodA时,必须由调用者方法生成Action / Func参数。 例:
MethodA(() => {});
4 。 在MethodA内部,我们现在可以调用上面定义的帮助器函数,并找到调用者方法的MethodInfo。
例:
MethodInfo callingMethodInfo = GetCallingMethodInfo(serverCall.Method.Name);
#4楼
尝试这个:
using System.Diagnostics;
// Get call stack
StackTrace stackTrace = new StackTrace();
// Get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);
它来自使用反射[C#]的Get调用方法 。
#5楼
请注意,由于优化,这样做在发行代码中将是不可靠的。 此外,在沙盒模式(网络共享)下运行该应用程序将根本不允许您抓住堆栈帧。
考虑一下像PostSharp这样的面向方面的编程 (AOP),而不是从代码中调用它,而是修改您的代码,从而始终知道它在哪里。
#6楼
看看.NET中的Logging方法名称 。 当心在生产代码中使用它。 StackFrame可能不可靠...
#7楼
通常,可以使用System.Diagnostics.StackTrace
类获取System.Diagnostics.StackFrame
,然后使用GetMethod()
方法获取System.Reflection.MethodBase
对象。 但是,此方法有一些警告 :
- 它代表运行时堆栈-优化可以内联一个方法,并且您不会在堆栈跟踪中看到该方法。
- 它不会显示任何本机框架,因此,即使有可能您的方法被本机方法调用,也将无法正常工作,并且实际上目前尚无可用的方法。
( 注意:我只是在扩展Firas Assad提供的答案 。)
#8楼
通过仅实例化我们实际需要的框架而不是整个堆栈,我们可以对阿萨德先生的代码(当前接受的答案)进行一些改进:
new StackFrame(1).GetMethod().Name;
这可能会更好一些,尽管很可能仍然必须使用完整的堆栈来创建单个帧。 而且,它仍然具有Alex Lyman指出的警告(优化器/本地代码可能会破坏结果)。 最后,您可能需要检查以确保new StackFrame(1)
或.GetFrame(1)
不会返回null
,这似乎不太可能。
看到这个相关的问题: 可以使用反射来查找当前正在执行的方法的名称吗?
#9楼
也许您正在寻找这样的东西:
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
#10楼
我使用的另一种方法是向有问题的方法添加参数。 例如,使用void Foo(string context)
代替void Foo()
void Foo(string context)
。 然后传递一些表示调用上下文的唯一字符串。
如果只需要调用者/上下文进行开发,则可以在发货前删除该param
。
#11楼
/// <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;
}
#12楼
var callingMethod = new StackFrame(1, true).GetMethod();
string source = callingMethod.ReflectedType.FullName + ": " + callingMethod.Name;
#13楼
从.NET 4.5开始,您可以使用“ 呼叫者信息”属性:
-
CallerFilePath
调用函数的源文件; -
CallerLineNumber
调用该函数的代码行; CallerMemberName
调用该函数的成员。public void WriteLine( [CallerFilePath] string callerFilePath = "", [CallerLineNumber] long callerLineNumber = 0, [CallerMemberName] string callerMember= "") { Debug.WriteLine( "Caller File Path: {0}, Caller Line Number: {1}, Caller Member: {2}", callerFilePath, callerLineNumber, callerMember); }
“ .NET Core”和“ .NET Standard”中也存在此功能。
参考文献
- Microsoft-呼叫者信息(C#)
- Microsoft-
CallerFilePathAttribute
类 - Microsoft-
CallerLineNumberAttribute
类 - Microsoft-
CallerMemberNameAttribute
类
#14楼
快速回顾两种方法,速度比较是重要的部分。
在编译时确定调用方
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);
}
使用堆栈确定调用方
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);
}
两种方法的比较
Time for 1,000,000 iterations with Attributes: 196 ms
Time for 1,000,000 iterations with StackTrace: 5096 ms
因此,您可以看到,使用属性快得多! 实际上快了将近25倍。
#15楼
显然,这是一个较晚的答案,但是如果您可以使用.NET 4.5或更高版本,那么我有一个更好的选择:
internal static void WriteInformation<T>(string text, [CallerMemberName]string method = "")
{
Console.WriteLine(DateTime.Now.ToString() + " => " + typeof(T).FullName + "." + method + ": " + text);
}
这将打印当前的日期和时间,后跟“ Namespace.ClassName.MethodName”,并以“:text”结尾。
样本输出:
6/17/2016 12:41:49 PM => WpfApplication.MainWindow..ctor: MainWindow initialized
样品使用:
Logger.WriteInformation<MainWindow>("MainWindow initialized");
#16楼
private static MethodBase GetCallingMethod()
{
return new StackFrame(2, false).GetMethod();
}
private static Type GetCallingType()
{
return new StackFrame(2, false).GetMethod().DeclaringType;
}
一个很棒的课程在这里: http : //www.csharp411.com/c-get-calling-method/
#17楼
要获取方法名称和类名称,请尝试以下操作:
public static void Call()
{
StackTrace stackTrace = new StackTrace();
var methodName = stackTrace.GetFrame(1).GetMethod();
var className = methodName.DeclaringType.Name.ToString();
Console.WriteLine(methodName.Name + "*****" + className );
}
#18楼
有关Firas Assaad答案的更多信息。
我已经使用了new StackFrame(1).GetMethod().Name;
在具有依赖项注入的.net core 2.1中,我将调用方法称为“开始”。
我尝试使用[System.Runtime.CompilerServices.CallerMemberName] string callerName = ""
,它为我提供了正确的调用方法
#19楼
在C#5中,您可以使用调用方信息获取该信息:
//using System.Runtime.CompilerServices;
public void SendError(string Message, [CallerMemberName] string callerName = "")
{
Console.WriteLine(callerName + "called me.");
}
您还可以获取[CallerFilePath]
和[CallerLineNumber]
。
标签:调用,string,找到,void,StackFrame,GetMethod,方法,method,Name 来源: https://blog.csdn.net/asdfgh0077/article/details/104080307