Question

Lors de la connexion à C #, comment puis-je connaître le nom de la méthode qui a appelé la méthode actuelle? Je sais tout sur System.Reflection.MethodBase.GetCurrentMethod(), mais je souhaite franchir une étape supplémentaire dans la trace de la pile. J'ai envisagé d'analyser la trace de la pile, mais j'espère trouver une méthode plus claire et plus claire, comme Assembly.GetCallingAssembly() sauf pour les méthodes.

Était-ce utile?

La solution

Essayez ceci:

using System.Diagnostics;
// Get call stack
StackTrace stackTrace = new StackTrace();

// Get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);

Il provient de Obtenir une méthode d'appel à l'aide de Reflection [C #] .

Autres conseils

En C # 5, vous pouvez obtenir ces informations à l'aide des informations sur l'appelant:

//using System.Runtime.CompilerServices;
public void SendError(string Message, [CallerMemberName] string callerName = "") 
{ 
    Console.WriteLine(callerName + "called me."); 
} 

Vous pouvez également obtenir les [CallerFilePath] et [CallerLineNumber].

Vous pouvez utiliser les informations sur l'appelant et les paramètres facultatifs:

public static string WhoseThere([CallerMemberName] string memberName = "")
{
       return memberName;
}

Ce test illustre ceci:

[Test]
public void Should_get_name_of_calling_method()
{
    var methodName = CachingHelpers.WhoseThere();
    Assert.That(methodName, Is.EqualTo("Should_get_name_of_calling_method"));
}

Alors que StackTrace fonctionne assez rapidement et ne pose pas de problème de performances dans la plupart des cas, les informations sur le demandeur sont beaucoup plus rapides encore. Sur un échantillon de 1000 itérations, je l'ai enregistré 40 fois plus vite.

Nous pouvons améliorer légèrement le code de M. Assad (la réponse actuellement acceptée) en instanciant uniquement le cadre dont nous avons réellement besoin plutôt que la totalité de la pile:

new StackFrame(1).GetMethod().Name;

Cela pourrait être un peu plus performant, même si, selon toute vraisemblance, il doit encore utiliser la pile complète pour créer ce seul cadre. En outre, il a toujours les mêmes réserves que Alex Lyman a souligné (optimiseur / code natif pourrait corrompre les résultats). Enfin, vous voudrez peut-être vérifier si new StackFrame(1) ou .GetFrame(1) ne renvoie pas null, aussi improbable que cela puisse paraître.

Voir cette question connexe: Pouvez-vous utiliser la réflexion pour trouver le nom de la méthode en cours d'exécution?

En général, vous pouvez utiliser le System.Diagnostics.StackTrace classe pour obtenir un System.Diagnostics.StackFrame , et utilisez ensuite la GetMethod() méthode pour obtenir un objet System.Reflection.MethodBase . Toutefois, il existe certaines mises en garde à cette approche:

  1. Cela représente la pile d'exécution - des optimisations pourraient intégrer une méthode et vous ne verrez pas cette méthode dans le suivi de la pile.
  2. ne montrera aucun cadre natif. Par conséquent, s'il existe une chance que votre méthode soit appelée par une méthode native, ne sera pas et il n’existe en fait aucun moyen de le faire.

( NOTE: je développe juste sur la réponse fournie par Firas Assad .)

Une récapitulation rapide des deux approches, la comparaison de la vitesse étant l’essentiel.

http://geekswithblogs.net /BlackRabbitCoder/archive/2013/07/25/c.net-little-wonders-getting-caller-information.aspx

Détermination de l'appelant au moment de la compilation

static void Log(object message, 
[CallerMemberName] string memberName = "",
[CallerFilePath] string fileName = "",
[CallerLineNumber] int lineNumber = 0)
{
    // we'll just use a simple Console write for now    
    Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, memberName, message);
}

Détermination de l'appelant à l'aide de la pile

static void Log(object message)
{
    // frame 1, true for source info
    StackFrame frame = new StackFrame(1, true);
    var method = frame.GetMethod();
    var fileName = frame.GetFileName();
    var lineNumber = frame.GetFileLineNumber();

    // we'll just use a simple Console write for now    
    Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, method.Name, message);
}

Comparaison des 2 approches

Time for 1,000,000 iterations with Attributes: 196 ms
Time for 1,000,000 iterations with StackTrace: 5096 ms
  

Donc, vous voyez, utiliser les attributs est beaucoup, beaucoup plus rapide! Près de 25x   plus rapide en fait.

À partir de .NET 4.5, vous pouvez utiliser Informations sur l'appelant Attributs:

  • CallerFilePath - La source fichier qui a appelé la fonction;
  • CallerLineNumber - Ligne de code qui a appelé la fonction;
  • CallerMemberName - Membre qui a appelé la fonction.

    public void WriteLine(
        [CallerFilePath] string callerFilePath = "", 
        [CallerLineNumber] long callerLineNumber = 0,
        [CallerMemberName] string callerMember= "")
    {
        Debug.WriteLine(
            "Caller File Path: {0}, Caller Line Number: {1}, Caller Member: {2}", 
            callerFilePath,
            callerLineNumber,
            callerMember);
    }
    

& nbsp;

Cette fonction est également présente dans " Core NET " et " .NET Standard ".

Références

  1. Microsoft - Informations sur l'appelant (C #)
  2. Microsoft - CallerFilePathAttribute Classe
  3. Microsoft - CallerLineNumberAttribute Classe
  4. Microsoft - CallerMemberNameAttribute Classe

Notez que cela ne sera pas fiable dans le code de version, à cause de l'optimisation. En outre, l’exécution de l’application en mode bac à sable (partage réseau) ne vous permettra pas de saisir le cadre de la pile.

Envisagez la programmation orientée aspect (AOP), comme PostSharp , qui au lieu d'être appelé à partir de votre code, modifie votre code et sait donc où il se trouve à tout moment.

/// <summary>
/// Returns the call that occurred just before the "GetCallingMethod".
/// </summary>
public static string GetCallingMethod()
{
   return GetCallingMethod("GetCallingMethod");
}

/// <summary>
/// Returns the call that occurred just before the the method specified.
/// </summary>
/// <param name="MethodAfter">The named method to see what happened just before it was called. (case sensitive)</param>
/// <returns>The method name.</returns>
public static string GetCallingMethod(string MethodAfter)
{
   string str = "";
   try
   {
      StackTrace st = new StackTrace();
      StackFrame[] frames = st.GetFrames();
      for (int i = 0; i < st.FrameCount - 1; i++)
      {
         if (frames[i].GetMethod().Name.Equals(MethodAfter))
         {
            if (!frames[i + 1].GetMethod().Name.Equals(MethodAfter)) // ignores overloaded methods.
            {
               str = frames[i + 1].GetMethod().ReflectedType.FullName + "." + frames[i + 1].GetMethod().Name;
               break;
            }
         }
      }
   }
   catch (Exception) { ; }
   return str;
}

Évidemment, la réponse est tardive, mais j’ai une meilleure option si vous pouvez utiliser .NET 4.5 ou plus:

internal static void WriteInformation<T>(string text, [CallerMemberName]string method = "")
{
    Console.WriteLine(DateTime.Now.ToString() + " => " + typeof(T).FullName + "." + method + ": " + text);
}

Ceci imprimera la date et l'heure actuelles, suivies de " Namespace.ClassName.MethodName " et se terminant par " ;: text " ;.
Exemple de sortie:

6/17/2016 12:41:49 PM => WpfApplication.MainWindow..ctor: MainWindow initialized

Exemple d'utilisation:

Logger.WriteInformation<MainWindow>("MainWindow initialized");

Peut-être cherchez-vous quelque chose comme ceci:

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
private static MethodBase GetCallingMethod()
{
  return new StackFrame(2, false).GetMethod();
}

private static Type GetCallingType()
{
  return new StackFrame(2, false).GetMethod().DeclaringType;
}

Une classe fantastique est ici: http://www.csharp411.com/c -get-call-method /

Une autre approche que j'ai utilisée consiste à ajouter un paramètre à la méthode en question. Par exemple, au lieu de void Foo(), utilisez void Foo(string context). Puis transmettez une chaîne unique qui indique le contexte d’appel.

Si vous n'avez besoin que de l'appelant / du contexte pour le développement, vous pouvez supprimer le param avant la livraison.

StackFrame caller = (new System.Diagnostics.StackTrace()).GetFrame(1);
string methodName = caller.GetMethod().Name;

sera suffisant, je pense.

Consultez nom de la méthode de journalisation dans .NET . . Attention à l'utiliser dans le code de production. StackFrame n'est peut-être pas fiable ...

Nous pouvons également utiliser le lambda pour trouver l'appelant.

Supposons que vous ayez défini une méthode:

public void MethodA()
    {
        /*
         * Method code here
         */
    }

et vous voulez trouver l'appelant.

1 . Changez la signature de la méthode pour avoir un paramètre de type Action (Func fonctionnera également):

public void MethodA(Action helperAction)
        {
            /*
             * Method code here
             */
        }

2 . Les noms Lambda ne sont pas générés aléatoirement. La règle semble être: & Gt; < CallerMethodName > __ X où CallerMethodName est remplacé par la fonction précédente et X est un index.

private MethodInfo GetCallingMethodInfo(string funcName)
    {
        return GetType().GetMethod(
              funcName.Substring(1,
                                funcName.IndexOf("&gt;", 1, StringComparison.Ordinal) - 1)
              );
    }

3 . Lorsque nous appelons MethodA, le paramètre Action / Func doit être généré par la méthode de l'appelant. Exemple:

MethodA(() => {});

4 . Dans MethodA, nous pouvons maintenant appeler la fonction d'assistance définie ci-dessus et trouver le MethodInfo de la méthode de l'appelant.

Exemple:

MethodInfo callingMethodInfo = GetCallingMethodInfo(serverCall.Method.Name);

Pour obtenir le nom de la méthode et le nom de la classe, essayez ceci:

    public static void Call()
    {
        StackTrace stackTrace = new StackTrace();

        var methodName = stackTrace.GetFrame(1).GetMethod();
        var className = methodName.DeclaringType.Name.ToString();

        Console.WriteLine(methodName.Name + "*****" + className );
    }

Informations supplémentaires sur la réponse de Firas Assaad.

J'ai utilisé new StackFrame(1).GetMethod().Name; dans .net Core 2.1 avec injection de dépendance et la méthode d'appel est appelée "Démarrer".

j'ai essayé avec [System.Runtime.CompilerServices.CallerMemberName] string callerName = "" et il me donne la méthode d'appel correcte

var callingMethod = new StackFrame(1, true).GetMethod();
string source = callingMethod.ReflectedType.FullName + ": " + callingMethod.Name;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top