Können Sie mit Reflection den Namen der aktuell ausgeführten Methode finden?

Wie der Titel sagt: Kann reflection Ihnen den Namen der aktuell ausgeführten Methode geben.

Ich neige dazu, nicht zu erraten, wegen des Heisenberg-Problems. Wie rufen Sie eine Methode auf, die Ihnen die aktuelle Methode anzeigt, ohne die aktuelle Methode zu ändern? Aber ich hoffe, dass mich jemand dort verraten kann.

Aktualisieren:

  • Teil 2: Könnte dies verwendet werden, um auch Code für eine Eigenschaft zu suchen?
  • Teil 3: Wie wäre die Aufführung?

Endergebnis
Ich habe über MethodBase.GetCurrentMethod () erfahren. Ich habe auch gelernt, dass ich nicht nur einen Stack-Trace erstellen kann, sondern auch genau den Frame, den ich brauche, wenn ich möchte.

Um dies innerhalb einer Eigenschaft zu verwenden, nehmen Sie einfach eine .Substring (4), um die “set_” oder “get_” zu entfernen.

Solutions Collecting From Web of "Können Sie mit Reflection den Namen der aktuell ausgeführten Methode finden?"

Ab .NET 4.5 können Sie auch [CallerMemberName] verwenden

Beispiel: ein Property Setter (um Teil 2 zu beantworten):

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

Der Compiler liefert passende String-Literale auf Callsites, so dass es im Grunde keinen Performance Overhead gibt.

Das von Lex zur Verfügung gestellte Snippet war ein wenig lang, daher möchte ich auf den wichtigen Teil hinweisen, da niemand sonst die exakt gleiche Technik verwendet hat:

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

Dies sollte identische Ergebnisse an die Methode MethodBase.GetCurrentMethod (). Name zurückgeben , aber es lohnt sich, darauf hinzuweisen, da ich dies einmal in seiner eigenen Methode mit Index 1 für die vorherige Methode implementieren und aus einer Reihe verschiedener Eigenschaften aufrufen könnte. Außerdem wird nur ein Frame und nicht der gesamte Stack-Trace zurückgegeben:

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

Es ist auch ein One-Liner;)

Versuchen Sie dies in der Main-Methode in einem leeren Konsolenprogramm:

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

Konsolenausgabe:
Main

Ja auf jeden Fall.

Wenn Sie ein Objekt manipulieren wollen, verwende ich eine function wie diese:

 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; } 

Diese Linie:

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

Geht den Stack-Frame hoch, um die aufrufende Methode zu finden, dann verwenden wir die Reflektion, um Parameterinformationen zu erhalten, die an ihn für eine generische Fehlerberichtsfunktion übergeben werden. Um die aktuelle Methode zu erhalten, verwenden Sie stattdessen den aktuellen Stapelrahmen (1).

Wie andere für den aktuellen Methodennamen gesagt haben, können Sie auch verwenden:

 MethodBase.GetCurrentMethod() 

Ich bevorzuge es, den Stack zu gehen, denn wenn ich intern auf diese Methode schaue, erstellt er einfach einen StackCrawlMark. Die direkte Ansprache des Stacks scheint mir klarer zu sein

Post 4.5 Sie können jetzt das [CallerMemberNameAttribute] als Teil der Methodenparameter verwenden, um eine Zeichenfolge des Methodennamens zu erhalten – dies kann in einigen Szenarien helfen (aber wirklich in dem obigen Beispiel)

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

Dies schien hauptsächlich eine Lösung für die InotifyPropertyChanged-Unterstützung zu sein, bei der Sie zuvor Strings über Ihren Event-Code verteilt hatten.

EDIT: MethodBase ist wahrscheinlich eine bessere Methode, um nur die Methode zu erhalten, in der Sie sich befinden (im Gegensatz zum gesamten Aufruf-Stack). Ich wäre jedoch immer noch besorgt um Inlining.

Sie können einen StackTrace innerhalb der Methode verwenden:

 StackTrace st = new StackTrace(true); 

Und der Blick auf die Rahmen:

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

Beachten Sie jedoch, dass Sie nicht in der Methode sind, die Sie für richtig halten. Sie können ein Attribut verwenden, um Inlining zu verhindern:

 [MethodImpl(MethodImplOptions.NoInlining)] 

Vergleichen von Methoden zum Abrufen des Methodennamens – Verwenden eines beliebigen Timing-Konstrukts in LinqPad:

CODE

 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; } } 

ERGEBNISSE

reflection reflection

Stapelverfolgung Stapelverfolgung

InlineConstant InlineConstant

Konstante konstant

Ausdruck e => e.expr ()

express

Anruferhaupt

 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 

Beachten Sie, dass die Methoden expr und callermember nicht ganz “richtig” sind. Und dort sehen Sie eine Wiederholung eines verwandten Kommentars, dass reflection ~ 15x schneller ist als StackTrace.

Wie wäre es damit:

 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 

Die einfache Art zu handeln ist:

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

Wenn die System.Reflection im using-Block enthalten ist:

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

Ich denke, du solltest das schaffen, wenn du einen StackTrace erstellst . Oder, wie @ edg und @ Lars Mæhlum erwähnen, MethodBase. GetCurrentMethod ()

Wenn Sie nur den String-Namen der Methode benötigen, können Sie Expressions verwenden. Siehe http://joelabrahamsson.com/entry/getting-property-and-method-names-using-static-reflection-in-c-sharp

Versuche dies…

  ///  /// 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); } 

Ich habe das mit einer einfachen statischen class gemacht:

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

dann in deinem Code:

 private void button1_Click(object sender, EventArgs e) { textBox1.Text = MyMethodName.Show(); } private void button2_Click(object sender, EventArgs e) { textBox1.Text = MyMethodName.Show(); }