Можете ли вы использовать reflection, чтобы найти имя текущего исполняемого метода?

Как и в заголовке, можно сказать: «Может ли reflection отразить имя текущего метода.

Я склонен не догадываться, из-за проблемы Гейзенберга. Как вы вызываете метод, который скажет вам текущий метод, не изменяя текущий метод? Но я надеюсь, что кто-то может доказать мне, что там не так.

Обновить:

  • Часть 2: Может ли это использоваться, чтобы заглянуть внутрь кода для свойства?
  • Часть 3: Каким будет представление?

Конечный результат
Я узнал о MethodBase.GetCurrentMethod (). Я также узнал, что не только могу создать трассировку стека, я могу создать только точный кадр, который мне нужен, если захочу.

Чтобы использовать это внутри свойства, просто возьмите .Substring (4), чтобы удалить «set_» или «get_».

Начиная с .NET 4.5 вы также можете использовать [CallerMemberName]

Пример: средство настройки свойств (для ответа на часть 2):

protected void SetProperty(T value, [CallerMemberName] string property = null) { this.propertyValues[property] = value; OnPropertyChanged(property); } public string SomeProperty { set { SetProperty(value); } } 

Компилятор будет поставлять соответствующие строковые литералы на звонках, поэтому накладные расходы в основном отсутствуют.

Фрагмент, предоставленный Лексом, был немного длинным, поэтому я указываю важную роль, поскольку никто другой не использовал точно такую ​​же технику:

 string MethodName = new StackFrame(0).GetMethod().Name; 

Это должно возвращать идентичные результаты методу MethodBase.GetCurrentMethod (). Name , но все же стоит отметить, потому что я смог реализовать это один раз в своем собственном методе с использованием индекса 1 для предыдущего метода и вызвать его из целого ряда различных свойств. Кроме того, он возвращает только один кадр, а не всю трассировку стека:

 private string GetPropertyName() { //.SubString(4) strips the property prefix (get|set) from the name return new StackFrame(1).GetMethod().Name.Substring(4); } 

Это тоже один лайнер;)

Попробуйте это внутри метода Main в пустой консольной программе:

 MethodBase method = MethodBase.GetCurrentMethod(); Console.WriteLine(method.Name); 

Консольный выход:
Main

Да, безусловно.

Если вы хотите, чтобы объект манипулировал, я действительно использую такую ​​функцию:

 public static T CreateWrapper(Exception innerException, params object[] parameterValues) where T : Exception, new() { if (parameterValues == null) { parameterValues = new object[0]; } Exception exception = null; StringBuilder builder = new StringBuilder(); MethodBase method = new StackFrame(2).GetMethod(); ParameterInfo[] parameters = method.GetParameters(); builder.AppendFormat(CultureInfo.InvariantCulture, ExceptionFormat, new object[] { method.DeclaringType.Name, method.Name }); if ((parameters.Length > 0) || (parameterValues.Length > 0)) { builder.Append(GetParameterList(parameters, parameterValues)); } exception = (Exception)Activator.CreateInstance(typeof(T), new object[] { builder.ToString(), innerException }); return (T)exception; } 

Эта строка:

 MethodBase method = new StackFrame(2).GetMethod(); 

Просматривает стек стека, чтобы найти вызывающий метод, затем мы используем reflection для получения значений информации о параметрах, переданных ему для общей функции сообщения об ошибках. Чтобы получить текущий метод, просто используйте текущий кадр стека (1).

Как и другие, для имени текущего метода вы также можете использовать:

 MethodBase.GetCurrentMethod() 

Я предпочитаю ходить в стеке, потому что, если вы смотрите внутри этого метода, он просто создает StackCrawlMark. Мне кажется, что мне кажется яснее обращаться к стеку

Post 4.5 теперь вы можете использовать параметр [CallerMemberNameAttribute] как часть параметров метода, чтобы получить строку имени метода – это может помочь в некоторых сценариях (но, действительно, в примере выше)

 public void Foo ([CallerMemberName] string methodName = null) 

Это, казалось, было главным образом решением для поддержки INotifyPropertyChanged, где раньше у вас были строки, замусоренные во всем коде события.

EDIT: MethodBase, вероятно, лучший способ просто получить метод, в котором вы находитесь (в отличие от всего вызывающего стека). Тем не менее я все равно буду беспокоиться о inlining.

Вы можете использовать StackTrace в методе:

 StackTrace st = new StackTrace(true); 

И посмотрите на frameworks:

 // The first frame will be the method you want (However, see caution below) st.GetFrames(); 

Однако имейте в виду, что если метод встроен, вы не будете внутри метода, который, по вашему мнению, вы. Вы можете использовать атрибут для предотвращения вложения:

 [MethodImpl(MethodImplOptions.NoInlining)] 

Сравнение способов получения имени метода – использование произвольной временной конструкции в LinqPad:

КОД

 void Main() { // from http://blogs.msdn.com/b/webdevelopertips/archive/2009/06/23/tip-83-did-you-know-you-can-get-the-name-of-the-calling-method-from-the-stack-using-reflection.aspx // and https://stackoverflow.com/questions/2652460/c-sharp-how-to-get-the-name-of-the-current-method-from-code var fn = new methods(); fn.reflection().Dump("reflection"); fn.stacktrace().Dump("stacktrace"); fn.inlineconstant().Dump("inlineconstant"); fn.constant().Dump("constant"); fn.expr().Dump("expr"); fn.exprmember().Dump("exprmember"); fn.callermember().Dump("callermember"); new Perf { { "reflection", n => fn.reflection() }, { "stacktrace", n => fn.stacktrace() }, { "inlineconstant", n => fn.inlineconstant() }, { "constant", n => fn.constant() }, { "expr", n => fn.expr() }, { "exprmember", n => fn.exprmember() }, { "callermember", n => fn.callermember() }, }.Vs("Method name retrieval"); } // Define other methods and classes here class methods { public string reflection() { return System.Reflection.MethodBase.GetCurrentMethod().Name; } public string stacktrace() { return new StackTrace().GetFrame(0).GetMethod().Name; } public string inlineconstant() { return "inlineconstant"; } const string CONSTANT_NAME = "constant"; public string constant() { return CONSTANT_NAME; } public string expr() { Expression> ex = e => e.expr(); return ex.ToString(); } public string exprmember() { return expressionName(e => e.exprmember); } protected string expressionName(Expression>> action) { // https://stackoverflow.com/a/9015598/1037948 return ((((action.Body as UnaryExpression).Operand as MethodCallExpression).Object as ConstantExpression).Value as MethodInfo).Name; } public string callermember([CallerMemberName]string name = null) { return name; } }

с void Main() { // from http://blogs.msdn.com/b/webdevelopertips/archive/2009/06/23/tip-83-did-you-know-you-can-get-the-name-of-the-calling-method-from-the-stack-using-reflection.aspx // and https://stackoverflow.com/questions/2652460/c-sharp-how-to-get-the-name-of-the-current-method-from-code var fn = new methods(); fn.reflection().Dump("reflection"); fn.stacktrace().Dump("stacktrace"); fn.inlineconstant().Dump("inlineconstant"); fn.constant().Dump("constant"); fn.expr().Dump("expr"); fn.exprmember().Dump("exprmember"); fn.callermember().Dump("callermember"); new Perf { { "reflection", n => fn.reflection() }, { "stacktrace", n => fn.stacktrace() }, { "inlineconstant", n => fn.inlineconstant() }, { "constant", n => fn.constant() }, { "expr", n => fn.expr() }, { "exprmember", n => fn.exprmember() }, { "callermember", n => fn.callermember() }, }.Vs("Method name retrieval"); } // Define other methods and classes here class methods { public string reflection() { return System.Reflection.MethodBase.GetCurrentMethod().Name; } public string stacktrace() { return new StackTrace().GetFrame(0).GetMethod().Name; } public string inlineconstant() { return "inlineconstant"; } const string CONSTANT_NAME = "constant"; public string constant() { return CONSTANT_NAME; } public string expr() { Expression> ex = e => e.expr(); return ex.ToString(); } public string exprmember() { return expressionName(e => e.exprmember); } protected string expressionName(Expression>> action) { // https://stackoverflow.com/a/9015598/1037948 return ((((action.Body as UnaryExpression).Operand as MethodCallExpression).Object as ConstantExpression).Value as MethodInfo).Name; } public string callermember([CallerMemberName]string name = null) { return name; } }

РЕЗУЛЬТАТЫ

reflection отражения

stacktrace stacktrace

inlineconstant inlineconstant

постоянная постоянная

expr e => e.expr ()

представитель экс-

Главная страница

 Method name retrieval: (reflection) vs (stacktrace) vs (inlineconstant) vs (constant) vs (expr) vs (exprmember) vs (callermember) 154673 ticks elapsed ( 15.4673 ms) - reflection 2588601 ticks elapsed (258.8601 ms) - stacktrace 1985 ticks elapsed ( 0.1985 ms) - inlineconstant 1385 ticks elapsed ( 0.1385 ms) - constant 1366706 ticks elapsed (136.6706 ms) - expr 775160 ticks elapsed ( 77.516 ms) - exprmember 2073 ticks elapsed ( 0.2073 ms) - callermember >> winner: constant 

Обратите внимание, что методы expr и callermember не совсем «правильные». И там вы видите повторение связанного комментария, что reflection ~ 15 раз быстрее, чем stacktrace.

Как насчет этого:

 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 

Простым способом решения является:

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

Если System.Reflection включен в блок использования:

 MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + MethodBase.GetCurrentMethod().Name; 

Я думаю, вы должны получить это от создания StackTrace . Или, как @ edg и @ Lars Mæhlum упоминают, MethodBase. GetCurrentMethod ()

Если вам нужно просто имя строки метода, вы можете использовать выражения. См. http://joelabrahamsson.com/entry/getting-property-and-method-names-using-static-reflection-in-c-sharp

Попробуй это…

  ///  /// Return the full name of method ///  /// Class that calls this method (use Report(this)) ///  public string Report(object obj) { var reflectedType = new StackTrace().GetFrame(1).GetMethod().ReflectedType; if (reflectedType == null) return null; var i = reflectedType.FullName; var ii = new StackTrace().GetFrame(1).GetMethod().Name; return string.Concat(i, ".", ii); } 

Я просто сделал это с помощью простого статического classа:

 using System.Runtime.CompilerServices; . . . public static class MyMethodName { public static string Show([CallerMemberName] string name = "") { return name; } } 

затем в вашем коде:

 private void button1_Click(object sender, EventArgs e) { textBox1.Text = MyMethodName.Show(); } private void button2_Click(object sender, EventArgs e) { textBox1.Text = MyMethodName.Show(); } 
  • Более быстрые альтернативы отражению Java
  • Есть ли способ получить псевдоним типа через reflection?
  • Как запретить разработчикам использовать reflection для доступа к приватным методам и конструкторам в Java?
  • Когда вы используете reflection? Модели / анти-паттерны
  • Получить общий тип classа во время выполнения
  • Быстрое создание объектов вместо Activator.CreateInstance (type)
  • Через 3 минуты Что такое reflection?
  • Вызов методов с необязательными параметрами посредством отражения
  • Поддержка отражения в C
  • Как использовать метод отражения для вызова по имени
  • Есть ли способ «переопределить» метод с reflectionм?
  • Давайте будем гением компьютера.