Comment trouver la méthode appelée méthode actuelle?

Lors de la connexion à C #, comment puis-je apprendre le nom de la méthode qui a appelé la méthode actuelle? Je sais tout sur System.Reflection.MethodBase.GetCurrentMethod() , mais je veux faire un pas en dessous dans la trace de la stack. J’ai envisagé d’parsingr la trace de la stack, mais j’espère trouver un moyen plus explicite, quelque chose comme Assembly.GetCallingAssembly() mais pour les méthodes.

    Essaye ça:

     using System.Diagnostics; // Get call stack StackTrace stackTrace = new StackTrace(); // Get calling method name Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name); 

    C’est de Get Calling Method utilisant Reflection [C #] .

    En C # 5, vous pouvez obtenir cette information en utilisant les informations de l’appelant:

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

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

    Vous pouvez utiliser les informations sur l’appelant et les parameters facultatifs:

     public static ssortingng WhoseThere([CallerMemberName] ssortingng 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")); } 

    Bien que le StackTrace fonctionne assez rapidement au-dessus et ne soit pas un problème de performances dans la plupart des cas, les informations sur l’appelant sont encore beaucoup plus rapides. Dans un échantillon de 1000 itérations, je l’ai noté 40 fois plus rapidement.

    En général, vous pouvez utiliser la classe System.Diagnostics.StackTrace pour obtenir un System.Diagnostics.StackFrame , puis utiliser la méthode GetMethod() pour obtenir un object System.Reflection.MethodBase . Cependant, cette approche comporte quelques réserves :

    1. Il représente la stack d’ exécution – les optimisations peuvent intégrer une méthode et vous ne verrez pas cette méthode dans la trace de la stack.
    2. Il ne montrera aucun cadre natif, donc s’il y a même une chance que votre méthode soit appelée par une méthode native, cela ne fonctionnera pas , et il n’y a en fait aucun moyen actuellement disponible pour le faire.

    ( NOTE: Je ne fais que développer la réponse fournie par Firas Assad .)

    Nous pouvons améliorer le code de M. Assad (la réponse acceptée actuellement) en instanciant seulement la trame dont nous avons réellement besoin plutôt que la stack entière:

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

    Cela pourrait être un peu mieux, mais il est fort probable que la stack complète soit nécessaire pour créer cette image unique. En outre, il a toujours les mêmes mises en garde que Alex Lyman a souligné (optimiseur / code natif peut corrompre les résultats). Enfin, vous voudrez peut-être vérifier que les new StackFrame(1) ou .GetFrame(1) ne renvoient pas null , aussi improbable que cela puisse paraître.

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

    Un rapide récapitulatif des 2 approches avec une comparaison de vitesse est la partie importante.

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

    Détermination de l’appelant à la compilation

     static void Log(object message, [CallerMemberName] ssortingng memberName = "", [CallerFilePath] ssortingng 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 stack

     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 Atsortingbutes: 196 ms Time for 1,000,000 iterations with StackTrace: 5096 ms 

    Donc, vous voyez, l’utilisation des atsortingbuts est beaucoup, beaucoup plus rapide! En fait, près de 25 fois plus vite.

    A partir de .NET 4.5, vous pouvez utiliser les atsortingbuts d’ informations de l’appelant :

    • CallerFilePath – Le fichier source 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] ssortingng callerFilePath = "", [CallerLineNumber] long callerLineNumber = 0, [CallerMemberName] ssortingng callerMember= "") { Debug.WriteLine( "Caller File Path: {0}, Caller Line Number: {1}, Caller Member: {2}", callerFilePath, callerLineNumber, callerMember); } 

    Cette fonctionnalité est également présente dans “.NET Core” et “.NET Standard”.

    Les références

    1. Microsoft – Informations sur l’appelant (C #)
    2. Microsoft – Classe CallerFilePathAtsortingbute
    3. Microsoft – Classe CallerLineNumberAtsortingbute
    4. Microsoft – Classe CallerMemberNameAtsortingbute

    Notez que cela ne sera pas fiable dans le code de la version, en raison de l’optimisation. En outre, l’exécution de l’application en mode sandbox (partage réseau) ne vous permettra pas de récupérer le cadre de la stack.

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

     ///  /// Returns the call that occurred just before the "GetCallingMethod". ///  public static ssortingng GetCallingMethod() { return GetCallingMethod("GetCallingMethod"); } ///  /// Returns the call that occurred just before the the method specified. ///  /// The named method to see what happened just before it was called. (case sensitive) /// The method name. public static ssortingng GetCallingMethod(ssortingng MethodAfter) { ssortingng 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; } 

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

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

    Cela affichera la date et l’heure actuelles, suivies de “Namespace.ClassName.MethodName” et se terminera par “: text”.
    Sortie de l’échantillon:

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

    Exemple d’utilisation:

     Logger.WriteInformation("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-calling-method/

    Une autre approche que j’ai utilisée consiste à append un paramètre à la méthode en question. Par exemple, au lieu de void Foo() , utilisez void Foo(ssortingng context) . Passez ensuite 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 de l’envoyer.

    Consultez le nom de la méthode de journalisation dans .NET . Attention à ne pas l’utiliser dans le code de production. StackFrame peut ne pas être fiable …

    Nous pouvons également utiliser des lambda pour trouver l’appelant.

    Supposons que vous ayez une méthode définie par vous:

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

    et vous voulez trouver son 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 de manière aléatoire. La règle semble être:> __ X où CallerMethodName est remplacé par la fonction précédente et X est un index.

     private MethodInfo GetCallingMethodInfo(ssortingng funcName) { return GetType().GetMethod( funcName.Subssortingng(1, funcName.IndexOf(">", 1, SsortingngComparison.Ordinal) - 1) ); } 

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

     MethodA(() => {}); 

    4 . A l’intérieur de MethodA, nous pouvons maintenant appeler la fonction d’assistance définie ci-dessus et trouver MethodInfo de la méthode de l’appelant.

    Exemple:

     MethodInfo callingMethodInfo = GetCallingMethodInfo(serverCall.Method.Name); 
     StackFrame caller = (new System.Diagnostics.StackTrace()).GetFrame(1); ssortingng methodName = caller.GetMethod().Name; 

    sera suffisant, je pense.

     var callingMethod = new StackFrame(1, true).GetMethod(); ssortingng source = callingMethod.ReflectedType.FullName + ": " + callingMethod.Name; 

    En l’appelant de cette façon, vous pouvez extraire des méthodes précédentes, même si cette méthode appartient à une autre application.

     public enum CALL_TYPE { ClassName, MethodName, PrevMethodName, ModuleName } ///  /// Get full namespace, class, and/or method name. ///  ///  ///  [MethodImpl(MethodImplOptions.NoInlining)] static public ssortingng GetReflection(CALL_TYPE type) { ssortingng retVal = ""; int STACK_FRAME = (type == CALL_TYPE.ClassName ? 1 : (int)type); STACK_FRAME = (type == CALL_TYPE.ModuleName ? 1 : STACK_FRAME); try { StackTrace st = new StackTrace(new StackFrame(STACK_FRAME)); switch (type) { case CALL_TYPE.ClassName: ssortingng[] allData = ssortingng.Format("{0}", st.GetFrame(0).GetMethod().ReflectedType.FullName).Split('.'); retVal = allData[allData.Length - 1]; break; case CALL_TYPE.MethodName: case CALL_TYPE.PrevMethodName: retVal = ssortingng.Format("{0}.{1}", st.GetFrame(0).GetMethod().ReflectedType.FullName, st.GetFrame(0).GetMethod().Name); break; case CALL_TYPE.ModuleName: retVal = st.GetFrame(0).GetMethod().Module.Name; break; } } catch { //unable to resortingeve method retVal = ""; } return retVal; } 

    En l’appelant:

     ssortingng currentMethod = GetReflection(CALL_TYPE.MethodName); 

    ou

     ssortingng prevtMethod = GetReflection(CALL_TYPE.PrevMethodName);