Можете ли вы использовать отражение, чтобы найти имя текущего исполняемого метода?
Как и заголовок говорит: Может ли отражение отразить имя текущего исполняемого метода.
Я склонен угадывать, из-за проблемы Гейзенберга. Как вы вызываете метод, который скажет вам текущий метод, не изменяя текущий метод? Но я надеюсь, что кто-то может доказать мне, что там не так.
Обновление:
- Часть 2: Может ли это использоваться для просмотра внутри кода для свойства?
- Часть 3: Каким будет представление производительности?
Конечный результат
Я узнал о MethodBase.GetCurrentMethod(). Я также узнал, что не только могу создать трассировку стека, я могу создать только точный кадр, который мне нужен, если захочу.
Чтобы использовать это внутри свойства, просто возьмите .Substring(4), чтобы удалить "set_" или "get_".
Ответы
Ответ 1
Начиная с .NET 4.5 вы также можете использовать [CallerMemberName]
Пример: установщик свойства (для ответа на часть 2):
protected void SetProperty<T>(T value, [CallerMemberName] string property = null)
{
this.propertyValues[property] = value;
OnPropertyChanged(property);
}
public string SomeProperty
{
set { SetProperty(value); }
}
Компилятор будет предоставлять совпадающие строковые литералы на сайтах вызовов, так что производительность практически не снижается.
Ответ 2
System.Reflection.MethodBase.GetCurrentMethod().Name;
http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getcurrentmethod.aspx
Ответ 3
Фрагмент, предоставленный Лексом, был немного длинным, поэтому я указываю важную роль, поскольку никто другой не использовал точно такую же технику:
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);
}
Это тоже однострочный;)
Ответ 4
Попробуйте это внутри метода Main в пустой консольной программе:
MethodBase method = MethodBase.GetCurrentMethod();
Console.WriteLine(method.Name);
Консольный выход:
Main
Ответ 5
Да, безусловно.
Если вы хотите, чтобы объект манипулировал, я действительно использую такую функцию:
public static T CreateWrapper<T>(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();
Продвигает фрейм стека, чтобы найти вызывающий метод, затем мы используем отражение для получения значений информации о параметрах, переданных ему для общей функции сообщения об ошибках. Чтобы получить текущий метод, просто используйте текущий кадр стека (1).
Как уже говорилось, для имени текущего метода вы также можете использовать:
MethodBase.GetCurrentMethod()
Я предпочитаю ходить в стеке, потому что, если вы смотрите внутри этого метода, он просто создает StackCrawlMark. Обращение к стеку прямо кажется мне более ясным
Post 4.5 теперь вы можете использовать [CallerMemberNameAttribute] как часть параметров метода, чтобы получить строку имени метода - это может помочь в некоторых сценариях (но на самом деле в примере выше)
public void Foo ([CallerMemberName] string methodName = null)
Это, казалось, было главным образом решением для поддержки INotifyPropertyChanged, где раньше у вас были строки, заполненные всем кодом вашего события.
Ответ 6
Сравнение способов получения имени метода - использование конструкции произвольного времени в 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<Func<methods, string>> ex = e => e.expr();
return ex.ToString();
}
public string exprmember() {
return expressionName<methods,string>(e => e.exprmember);
}
protected string expressionName<T,P>(Expression<Func<T,Func<P>>> 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;
}
}
РЕЗУЛЬТАТЫ
отражение
отражение
StackTrace
трассировка стека
inlineconstant
встроенная константа
постоянная
постоянная
выраж
e => e.expr()
exprmember
exprmember
callermember
Главная
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
не совсем "правильные". И там вы видите повторение соответствующего комментария о том, что отражение в ~ 15 раз быстрее, чем трассировка стека.
Ответ 7
EDIT: MethodBase, вероятно, лучший способ просто получить метод, в котором вы находитесь (в отличие от всего вызывающего стека). Тем не менее, я все равно буду беспокоиться о вложениях.
Вы можете использовать StackTrace в рамках метода:
StackTrace st = new StackTrace(true);
И посмотрите на рамки:
// The first frame will be the method you want (However, see caution below)
st.GetFrames();
Однако имейте в виду, что если метод встроен, вы не будете внутри метода, который, по вашему мнению, вы. Вы можете использовать атрибут, чтобы предотвратить inlining:
[MethodImpl(MethodImplOptions.NoInlining)]
Ответ 8
Простым способом решения является:
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + System.Reflection.MethodBase.GetCurrentMethod().Name;
Если System.Reflection включен в блок использования:
MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + MethodBase.GetCurrentMethod().Name;
Ответ 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
Я думаю, вы сможете получить это от создания StackTrace. Или, как @edg и @Lars Mæhlum, укажите MethodBase. GetCurrentMethod()
Ответ 11
Если вам нужно просто имя строки метода, вы можете использовать выражения. См. http://joelabrahamsson.com/entry/getting-property-and-method-names-using-static-reflection-in-c-sharp
Ответ 12
Попробуйте это...
/// <summary>
/// Return the full name of method
/// </summary>
/// <param name="obj">Class that calls this method (use Report(this))</param>
/// <returns></returns>
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);
}
Ответ 13
Я просто сделал это с помощью простого статического класса:
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();
}
Ответ 14
new StackTrace(). ToString(). Split ("\ r\n", StringSplitOptions.RemoveEmptyEntries) [0].Replace("at", ""). Trim()