Можете ли вы использовать reflection, чтобы найти имя текущего исполняемого метода?
Как и в заголовке, можно сказать: «Может ли reflection отразить имя текущего метода.
Я склонен не догадываться, из-за проблемы Гейзенберга. Как вы вызываете метод, который скажет вам текущий метод, не изменяя текущий метод? Но я надеюсь, что кто-то может доказать мне, что там не так.
Обновить:
- Поиск различий свойств между двумя объектами C #
- Как получить свойство Static с reflectionм
- Найти методы, которые имеют настраиваемый атрибут с использованием отражения
- Почему C ++ не имеет отражения?
- Как передать функцию в качестве параметра в C #?
- Часть 2: Может ли это использоваться, чтобы заглянуть внутрь кода для свойства?
- Часть 3: Каким будет представление?
Конечный результат
Я узнал о MethodBase.GetCurrentMethod (). Я также узнал, что не только могу создать трассировку стека, я могу создать только точный кадр, который мне нужен, если захочу.
Чтобы использовать это внутри свойства, просто возьмите .Substring (4), чтобы удалить «set_» или «get_».
- Избегание instanceof в Java
- Как скопировать значение из classа X в class Y с тем же именем свойства в c #?
- Как скрыть общественные методы от intellisense
- Как найти все classы, реализующие данный интерфейс?
- Почему TargetInvocationException рассматривается как неотображаемое средой IDE?
- Как я могу оценивать выражение C # динамически?
- Как вы можете перебирать свойства classа?
- Проверьте, существует ли свойство в classе
Начиная с .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); } }
Компилятор будет поставлять соответствующие строковые литералы на звонках, поэтому накладные расходы в основном отсутствуют.
System.Reflection.MethodBase.GetCurrentMethod().Name;
http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getcurrentmethod.aspx
Фрагмент, предоставленный Лексом, был немного длинным, поэтому я указываю важную роль, поскольку никто другой не использовал точно такую же технику:
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(); }