当前位置:  开发笔记 > 编程语言 > 正文

如何找到调用当前方法的方法?

如何解决《如何找到调用当前方法的方法?》经验,为你挑选了11个好方法。

登录C#时,如何学习调用当前方法的方法的名称?我知道所有这些System.Reflection.MethodBase.GetCurrentMethod(),但我想在堆栈跟踪中向下迈出一步.我考虑过解析堆栈跟踪,但我希望找到一种更清晰,更明确的方法,比如Assembly.GetCallingAssembly()方法.



1> Firas Assaad..:

试试这个:

using System.Diagnostics;
// Get call stack
StackTrace stackTrace = new StackTrace();

// Get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);

它来自使用反射[C#]的Get Calling Method.


new StackFrame(1).GetMethod().Name;
我过去所做的是在查找堆栈跟踪的方法之前添加编译器属性*[MethodImplAttribute(MethodImplOptions.NoInlining)]*.这可以确保编译器不会内联该方法,并且堆栈跟踪将包含真正的调用方法(在大多数情况下,我并不担心尾递归.)
您也可以只创建所需的帧,而不是整个堆栈:
但这并不完全可靠.让我们看看这是否适用于评论!在控制台应用程序中尝试以下操作,您会发现编译器操作会破坏它.static void Main(string [] args){CallIt(); } private static void CallIt(){Final(); } void void Final(){StackTrace trace = new StackTrace(); StackFrame frame = trace.GetFrame(1); Console.WriteLine("{0}.{1}()",frame.GetMethod().DeclaringType.FullName,frame.GetMethod().Name); }
当编译器内联或尾调用优化方法时,这不起作用,在这种情况下,堆栈将折叠,您将找到除预期之外的其他值.当你只在Debug版本中使用它时,它会很好用.
但编译器可能会内联调用方法.

2> Coincoin..:

在C#5中,您可以使用来电者信息获取该信息:

//using System.Runtime.CompilerServices;
public void SendError(string Message, [CallerMemberName] string callerName = "") 
{ 
    Console.WriteLine(callerName + "called me."); 
} 

你也可以得到[CallerFilePath][CallerLineNumber].


@AFract语言(C#)版本与.NET版本不同.
您好,它不是C#5,它在4.5中可用.
@stuartd看起来`[CallerTypeName]`从当前的.Net框架(4.6.2)和Core CLR中删除了
@ Ph0en1x它永远不会出现在框架中,我的观点是,如果是这样的话会很方便,例如[如何获得CallerMember的类型名称](http://stackoverflow.com/questions/17893827/c-sharp-how-对获得型名称的-A-callermember)
@DiegoDeberdt-我已经读到,使用它不会产生任何负面影响,因为它可以在编译时完成所有工作。我相信所谓的方法是准确的。

3> dove..:

您可以使用来电者信息和可选参数:

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的工作速度非常快,但在大多数情况下都不会出现性能问题,但Caller Information的速度要快得多.在1000次迭代的样本中,我将其计时速度提高了40倍.


应该作为现代化的方式经常受到欢迎.
这是完美的,并且对异步非常友好,而StackFrame不会帮您。也不会影响从lambda调用。

4> Joel Coehoor..:

我们可以通过仅实例化我们实际需要的帧而不是整个堆栈来改进阿萨德先生的代码(当前接受的答案):

new StackFrame(1).GetMethod().Name;

这可能会更好一点,但很可能它仍然必须使用完整堆栈来创建该单帧.此外,它仍然有Alex Lyman指出的相同警告(优化器/本机代码可能会破坏结果).最后,您可能希望检查以确定new StackFrame(1).GetFrame(1)不返回null,因为这种可能性看起来不太可能.

请参阅此相关问题: 您是否可以使用反射来查找当前正在执行的方法的名称?



5> Alex Lyman..:

通常,您可以使用System.Diagnostics.StackTrace该类获取a System.Diagnostics.StackFrame,然后使用该GetMethod()方法获取System.Reflection.MethodBase对象.但是,这种方法有一些注意事项:

    它表示运行时堆栈 - 优化可以内联方法,并且您不会在堆栈跟踪中看到该方法.

    不会显示任何原生帧,所以如果你的方法有可能被本机方法调用,这将无法工作,实际上目前还没有可行的方法.

(注意:我只是扩展了Firas Assad提供的答案.)


在关闭优化的调试模式下,您是否能够看到堆栈跟踪中的方法是什么?

6> Tikall..:

快速回顾两种方法,速度比较是重要的部分.

http://geekswithblogs.net/BlackRabbitCoder/archive/2013/07/25/c.net-little-wonders-getting-caller-information.aspx

在编译时确定调用者

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倍.



7> 小智..:

从.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"中.

参考

    微软 - 来电者信息(C#)

    微软 - CallerFilePathAttribute班级

    微软 - CallerLineNumberAttribute班级

    微软 - CallerMemberNameAttribute班级



8> angry person..:

请注意,由于优化,这样做在发布代码中将是不可靠的.此外,以沙箱模式(网络共享)运行应用程序将不允许您抓取堆栈帧.

考虑面向方面编程(AOP),如PostSharp,它不是从代码中调用,而是修改代码,从而随时了解它的位置.



9> SO used to b..:

显然这是一个迟到的答案,但如果您可以使用.NET 4.5或更高版本,我有更好的选择:

internal static void WriteInformation(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 initialized");



10> 小智..:
/// 
/// Returns the call that occurred just before the "GetCallingMethod".
/// 
public static string GetCallingMethod()
{
   return GetCallingMethod("GetCallingMethod");
}

/// 
/// Returns the call that occurred just before the the method specified.
/// 
/// The named method to see what happened just before it was called. (case sensitive)
/// The method name.
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;
}



11> jesal..:

也许你正在寻找这样的东西:

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

推荐阅读
低调pasta_730
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有