Как получить имя текущего метода из кода

Я знаю, что ты можешь сделать

this.GetType().FullName

Получить

My.Current.Class

Но что я могу позвонить, чтобы получить

My.Current.Class.CurrentMethod

person Nick Allen    schedule 16.04.2010    source источник
comment
this.ToString() дает вам текущее имя класса только в том случае, если вы не сделали ничего особенного в своем собственном public override string ToString(). GetType().FullName всегда дает вам полное имя.   -  person Pasi Savolainen    schedule 16.04.2010
comment
@Pasi спасибо, изменю мою реализацию   -  person Nick Allen    schedule 16.04.2010
comment
В .Net 4.5 вы можете использовать CallerMemberNameAttribute, чтобы получить имя вызывающего. См. msdn.microsoft. com / en-us / library / ... Затем вы можете заключить тело вашей функции в анонимную функцию, как в ([CallerMemberName] string functionName =) = ›{}. Проблемы с использованием метода отражения, как в принятом ответе, заключаются в том, что (1) функция может быть встроена и / или (2) имя функции может быть скрыто, если оно не является общедоступным и код скрыт.   -  person GreatAndPowerfulOz    schedule 05.03.2016
comment
Не совсем повторяющийся вопрос. Исходный вопрос касается именно «отражения». Некоторые ответы здесь не основаны на размышлениях.   -  person Jahmic    schedule 25.09.2019
comment
Для поддержки асинхронных методов вы можете использовать GetCurrentMethodFullName () из Использование System.Reflection для получения полного имени метода   -  person Michael Freidgeim    schedule 22.06.2021


Ответы (7)


using System.Diagnostics;
...

var st = new StackTrace();
var sf = st.GetFrame(0);

var currentMethodName = sf.GetMethod();

Или, если вы хотите иметь вспомогательный метод:

[MethodImpl(MethodImplOptions.NoInlining)]
public string GetCurrentMethod()
{
    var st = new StackTrace();
    var sf = st.GetFrame(1);

    return sf.GetMethod().Name;
}

Обновлено с благодарностью за @stusmith.

person Community    schedule 16.04.2010
comment
Имейте в виду, что JIT может использовать встроенные методы, которые могут этого не делать. Чтобы заставить метод не быть встроенным, добавьте атрибут [MethodImpl (MethodImplOptions.NoInlining)]. - person stusmith; 16.04.2010
comment
Обратите внимание, что добавление MethodImpl(MethodImplOptions.NoInlining) к GetCurrentMethod только предотвращает встраивание этого метода в его вызывающий объект. Это не препятствует тому, чтобы сам вызывающий метод был встроен в его собственный вызывающий объект и т. Д. И т. Д. - person LukeH; 16.04.2010
comment
@ Люк: Это, конечно, возможно и все усложняет. - person ; 16.04.2010
comment
Извините, да, я не понял - вам нужно добавить атрибут к методу, для которого вы хотите узнать имя. - person stusmith; 16.04.2010
comment
@stusmith: GetCurrentMethod тоже понадобится атрибут, верно? Он также может стать встроенным, почему бы и нет. - person ; 16.04.2010
comment
К вашему сведению, это не компилируется, поскольку sf.GetMethod() не является строкой. - person Hamish Grubijan; 03.05.2012
comment
Всегда ли этот метод возвращает GetCurrentMethod, поскольку он помещается поверх вызывающего объекта в стек, когда мы действительно хотим вернуть имя вызывающего? - person Candy Chiu; 26.07.2012
comment
@CandyChiu, нет. Обратите внимание, что они получают второй кадр (GetFrame(1)) - person Jonathon Reinhart; 07.08.2012
comment
@Hamish: в последней строке вспомогательного метода есть ошибка. Вероятно, он должен читать что-то вроде return sf.GetMethod().Name. Как указано выше @LukeH, если вы хотите, чтобы это было пуленепробиваемым, я подозреваю, вам также необходимо пометить любой метод, который вызывает его, с помощью MethodImpl(MethodImplOptions.NoInlining) (если вы не уверены, что он не будет встроен (например, метод, представленный как public) - person rkagerer; 16.01.2013
comment
re: одобренный комментарий @stusmith - я видел в другом месте, которое атрибут [MethodImpl(...NoInlining)] не имеет ' t всегда работает, если компилятор оптимизирует StackTrace. - person drzaus; 23.01.2014
comment
Мне не удалось найти решение, работающее с кодом выпуска. В режиме отладки встраивание не так агрессивно, и [MethodImpl(MethodImplOptions.NoInlining)], кажется, работает хорошо, но когда я перехожу в режим выпуска, все ставки кажутся отключенными, и NoInlining, кажется, рассматривается как подсказка? - person snowcode; 05.11.2014
comment
Только что поговорил с коллегой, который указал, что моя проблема заключалась в том, что я не помещал NoInlining на всех вызывающих абонентов на всем пути вверх по дереву. Дох! (конечно!) Это раздражает, поскольку большинство случаев использования, в которых мне нужно GetMethod(), - это помощники при приемке, и требование, чтобы все вызывающие абоненты имели NoInlining, код становится беспорядочным и трудным для сканирования. В любом случае, комментарий моих коллег объяснил, почему мой код иногда был встроен, несмотря на то, что метод отмечен атрибутом. Я не удалял свой комментарий выше, на случай, если у кого-то такая же проблема. - person snowcode; 05.11.2014
comment
В C # версии 6 есть новая функция nameof(), которую также можно использовать для этой цели: nameof(this.YourCurrentMethod); https://msdn.microsoft.com/en-us/library/dn986596.aspx - person Fabio; 06.02.2016
comment
А еще есть CallerMemberNameAttribute stackoverflow.com/a/15310053/58768 - person bohdan_trotsenko; 17.03.2016
comment
Это предполагает позицию в стеке текущего метода и ненадежно. Решение Джейми Айдэ является правильным. - person Antony Booth; 14.09.2016
comment
@AntonyBooth, посмотри комментарий над тобой - так лучше. (Использует [CallerMemberName] и может использоваться в статическом методе, чтобы получить его где угодно) - person Ori Nachum; 18.01.2017
comment
Это не работает, если метод имеет тип возврата Task, вам нужно использовать GetFrame (3). GetFrame (1) - это MoveNext, GetFrame (2) - начало. например общедоступная асинхронная задача TestMigrateData () - person Justin; 25.02.2019
comment
Не работает в приложениях UWP - person HelloWindowsPhone; 16.06.2019
comment
вы можете просто использовать new StackFrame().GetMethod(), он короче new StackTrace().GetFrame(0).GetMethod() и делает то же самое. - person Jason C; 25.05.2021

Вызов System.Reflection.MethodBase.GetCurrentMethod().Name из метода.

person Jamie Ide    schedule 16.04.2010
comment
Страдает ли это от встраивания? - person Gusdor; 23.06.2016
comment
Если вам интересно, какой из них быстрее, Reflection или StackTrace проверьте это: stackoverflow.com/a/1348853/495455 - person Jeremy Thompson; 26.05.2017
comment
Чтобы сэкономить время, перейдите по ссылке выше: StackTrace работает быстрее. - person Konrad; 27.11.2017
comment
Просто убедитесь, что вы добавили [MethodImpl (MethodImplOptions.NoInlining)] в качестве декоратора к методу, из которого вы вызываете это, иначе это не сработает. Спасибо - person erionpc; 19.12.2017
comment
@Konrad В посте StackTrace дает значительно более медленные результаты. Единственный сценарий, в котором это дает более быстрые результаты, - это когда отражение не сравнивается ни с чем. Используя BenchmarkDotNet, я протестировал MethodBase.GetCurrentMethod().Name против new StackFrame(0).GetMethod().Name, где отражение использовалось в среднем 1,5 мкс, а StackTrace использовало 11,5 мкс. - person 404; 21.01.2019
comment
@ Bleep-Bloop это зависит, в посте много «если». - person Konrad; 21.01.2019

Начиная с C # версии 6, вы можете просто позвонить:

string currentMethodName = nameof(MyMethod);

В C # версии 5 и .NET 4.5 вы можете использовать [ CallerMemberName], чтобы компилятор автоматически генерировал имя вызывающего метода в строковом аргументе. Другие полезные атрибуты: [CallerFilePath], чтобы компилятор сгенерировал путь к файлу исходного кода, и [CallerLineNumber], чтобы получить номер строки в файле исходного кода для оператора, сделавшего вызов.


До этого были еще несколько запутанных способов получить имя метода, но намного проще:

void MyMethod() {
  string currentMethodName = "MyMethod";
  //etc...
}

Хотя рефакторинг, вероятно, не исправит это автоматически.

Если вас совершенно не заботит (значительная) стоимость использования Reflection, тогда вам может пригодиться этот вспомогательный метод:

using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Reflection;
//...

[MethodImpl(MethodImplOptions.NoInlining)]
public static string GetMyMethodName() {
  var st = new StackTrace(new StackFrame(1));
  return st.GetFrame(0).GetMethod().Name;
} 
person Hans Passant    schedule 16.04.2010
comment
Я делал это раньше. Может быть нелегко поддерживать, если вы делаете это в масштабе всего приложения, но в остальном: простые удары умны в любой день! - person Daren Thomas; 16.04.2010
comment
Верные слова, это примерно в 10 000 раз быстрее, плюс-минус в 10 раз. - person Hans Passant; 16.04.2010
comment
+1 за подсказку [CallerMemberNameAttribute] .NET 4.5. Спасибо. - person Dylan Hogg; 22.07.2013
comment
CallerMemberName не будет работать для перегруженных методов. - person Onur Omer; 05.09.2015
comment
Мне кажется, ваш второй ответ должен быть вторым ответом, а не редактированием. Сейчас ваш второй ответ скрыт в большом ответе, и читатель может пропустить вторую часть. - person SandRock; 13.01.2016
comment
В C # версии 6 есть новая функция nameof(), которую также можно использовать для этой цели: nameof(this.YourCurrentMethod); https://msdn.microsoft.com/en-us/library/dn986596.aspx - person Fabio; 06.02.2016
comment
Ганс, почему в этом ответе используется более короткая версия? stackoverflow.com/a/44215/2377343 - person T.Todua; 27.09.2017
comment
Потому что в этом ответе не используется отдельный метод, как у меня. - person Hans Passant; 27.09.2017
comment
Есть ли современный сокращенный вызов имени класса, к которому принадлежит метод, как в Обновлении 2? - person ajeh; 13.04.2018
comment
CallerMemberName работает для .NETCore 2.0 в методах Async. Идеально. - person Andy; 22.04.2018

Я думаю, что лучший способ получить полное имя:

 this.GetType().FullName + "." + System.Reflection.MethodBase.GetCurrentMethod().Name;

или попробуйте это

string method = string.Format("{0}.{1}", MethodBase.GetCurrentMethod().DeclaringType.FullName, MethodBase.GetCurrentMethod().Name);   
person Zakaria    schedule 09.06.2013
comment
+1, потому что использование отражения на несколько порядков быстрее, чем использование StackTrace. - person Giuseppe Romagnuolo; 08.02.2014
comment
Это не работает для async методов. Я вызываю System.Reflection.MethodBase.GetCurrentMethod().Name в первой строке метода и получаю MoveNext. - person Gusdor; 23.06.2016
comment
Можно ли создать функцию, которая будет возвращать класс / имя функции вызывающего абонента? У вас отличное решение, но оно требует вызова каждый раз. Было бы идеально, если бы это могло быть в каком-то другом классе и общедоступной функции или, возможно, в общедоступном свойстве, которое можно было бы вызвать. В идеале в каком-то статическом классе. - person FrenkyB; 30.09.2016
comment
@FrenkyB - используйте атрибут [CallerMemberName] во вспомогательной функции. - person andrew; 10.11.2017
comment
Для методов async я добавил ответ здесь stackoverflow.com/questions/44153/ - person Useme Alehosaini; 03.05.2021

Это не работает?

System.Reflection.MethodBase.GetCurrentMethod()

Возвращает объект MethodBase, представляющий текущий выполняющийся метод.

Пространство имен: System.Reflection

Сборка: mscorlib (в mscorlib.dll)

http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getcurrentmethod.aspx

person Orwellophile    schedule 21.06.2012
comment
Не для async методов - person Devnsyde; 14.05.2020
comment
@Devnsyde для async методов, пожалуйста, посетите мой ответ в stackoverflow.com/questions/44153/ - person Useme Alehosaini; 03.05.2021

Вы также можете использовать MethodBase.GetCurrentMethod(), что запретит компилятору JIT встраивать метод, в котором он используется.


Обновление:

Этот метод содержит специальное перечисление StackCrawlMark, которое, насколько я понимаю, укажет JIT-компилятору, что текущий метод не должен быть встроен.

Это моя интерпретация комментария, связанного с этим перечислением в SSCLI. Комментарий следует:

// declaring a local var of this enum type and passing it by ref into a function 
// that needs to do a stack crawl will both prevent inlining of the calle and 
// pass an ESP point to stack crawl to
// 
// Declaring these in EH clauses is illegal; 
// they must declared in the main method body
person João Angelo    schedule 16.04.2010
comment
У вас есть ссылка, объясняющая, как GetCurrentMethod запрещает JIT встраивать вызывающий метод? - person LukeH; 16.04.2010
comment
@Luke, я обновил свой ответ, указав причину, по которой я считаю, что этот метод будет препятствовать встраиванию. - person João Angelo; 16.04.2010
comment
Спасибо, это очень интересно, хотя мне не совсем понятно, предотвращает ли это встраивание метода, объявляющего локальный StackCrawlMark, или вызывающего его метода. - person LukeH; 16.04.2010
comment
@ Люк, да, это может вызвать определенные сомнения, но поскольку сам GetCurrentMethod украшен [MethodImpl(MethodImplOptions.NoInlining)], я считаю, что это вызывающий метод, содержащий перечисление. - person João Angelo; 16.04.2010

Что ж, System.Reflection.MethodBase.GetCurrentMethod().Name - не очень хороший выбор, потому что он просто отображает имя метода без дополнительной информации.

Как и для string MyMethod(string str), указанное выше свойство вернет только MyMethod, что вряд ли достаточно.

Лучше использовать System.Reflection.MethodBase.GetCurrentMethod().ToString(), который вернет всю подпись метода ...

person Arefin    schedule 06.02.2013
comment
Вместо имени моего метода я получаю MoveNext. - person Marek Bar; 16.01.2017
comment
Для асинхронных методов это дает MoveNext - person shivesh suman; 22.11.2018