2010-07-20 4 views
22

Dire que j'ai une méthode:Y at-il un moyen d'obtenir un tableau des arguments passés à une méthode?

public void SomeMethod(String p1, String p2, int p3) 
{ 

#if DEBUG 
    object[] args = GetArguments(); 
    LogParamaters(args); 
#endif 

    // Do Normal stuff in the method 
} 

est-il un moyen de récupérer un tableau des arguments passés dans la méthode, afin qu'ils puissent être enregistrés?

J'ai un grand nombre de méthodes et que vous voulez éviter de passer manuellement les arguments par nom à l'enregistreur, comme l'erreur humaine se glissera inévitablement

Je devine que cela impliquera une réflexion sous une forme -. Qui est bien, car il ne sera utilisé qu'à des fins de débogage.

Mise à jour

Un peu plus d'informations:

Je ne peux pas changer la signature de la méthode de SomeMethod, comme il est exposé comme WebMethod et doit reproduire le système existant, il emprunte l'identité. Le système hérité enregistre déjà les arguments transmis. Pour commencer, la nouvelle implémentation encapsulera le système hérité, donc je cherche à enregistrer les paramètres entrant dans la version C#, afin que je puisse vérifier la bonne les paramètres sont passés dans le bon ordre.

Je suis à la recherche d'enregistrer les valeurs de l'argument et l'ordre, et non pas leurs noms.

+0

Quelles informations sur les paramètres sont stockés dans le journal? type, nom, valeur? – devnull

+0

cela signifie que vous parlez vraiment de _arguments_, pas de _parameters_. [(Voir par exemple ici pour une explication sur la différence.)] (Http://msdn.microsoft.com/en-us/library/9kewt1b3%28VS.80%29.aspx) – stakx

+0

@stax, oui cette distinction a du sens . Je cherche les valeurs d'argument passées dans la méthode. –

Répondre

0

Voici ce que je suis venu avec comme solution:

PostSharp ou d'une autre solution AOP n'était pas vraiment pratique dans cette situation, donc malheureusement je dû abandonner cette idée.

Il apparaît que si il est possible de paramétrer les noms et les types à l'aide de la réflexion, la seule façon d'accéder aux valeurs d'exécution est avec un débogueur attaché.

Voir ici pour plus d'informations:

StackOverflow

microsoft.public.dotnet.framework

Alors que toujours me reste le problème des 50 ~ méthodes qui avait besoin de cette exploitation forestière en ajoutant à la main.

réflexion au secours ...

public String GetMethodParameterArray() 
    { 
     var output = new StringBuilder(); 
     output.AppendLine(); 

     Type t = typeof(API); 
     foreach (var mi in t.GetMethods()) 
     { 
       var argsLine = new StringBuilder(); 
       bool isFirst = true; 
       argsLine.Append("object[] args = {"); 
       var args = mi.GetParameters(); 

       foreach (var pi in args) 
       { 
        if (isFirst) 
        { 
         isFirst = false; 
        } 
        else 
        { 
         argsLine.Append(", "); 
        } 
        argsLine.AppendFormat("{0}", pi.Name); 
       } 
       argsLine.AppendLine("};"); //close object[] initialiser 

       output.AppendLine(argsLine.ToString()); 
       output.AppendFormat("Log(\"{0}\",args);", mi.Name); 
       output.AppendLine(); 
       output.AppendLine(); 
      } 
     return output.ToString(); 
    } 

Cet extrait de code en boucle à travers les méthodes d'une classe et délivre en sortie un objet array [] initialisée avec les arguments passés à la méthode et un appel de journal qui contient les arguments et le nom de la méthode.

Exemple de sortie:

object[] args = {username, password, name, startDate, endDate, cost}; 
Log("GetAwesomeData",args); 

Ce bloc peut ensuite être collé dans la partie supérieure de la méthode pour obtenir l'effet recherché.

C'est plus manuel que ce que j'aurais aimé, mais c'est beaucoup mieux que d'avoir à taper les paramètres à la main et beaucoup moins sujet aux erreurs.

0

Il y a certaines fonctionnalités avec le système de type dynamique qui peut le faire, mais a besoin de votre classe pour hériter des classes de base dynamiques

+0

Avez-vous même lu la question? Il veut enregistrer tous les paramètres entrant dans une fonction et souhaite accéder à ces données. – Oded

1

Eh bien, si vous voulez juste transmettre les valeurs, vous pouvez tricher et définir un tableau d'objets:

public static void LogParameters(params object[] vals) 
{ 

} 

Ceci entraînera une mise en boîte sur les types de valeur et ne vous donnera pas non plus de noms de paramètres.

Dire que j'ai une méthode:

public void SomeMethod(String p1, String p2, int p3) 
{ 

#if DEBUG 
    LogParamaters(p1, p2, p3); 
#endif 

    // Do Normal stuff in the method 
} 

Mise à jour: malheureusement la réflexion ne sera pas tout faire automatiquement pour vous. Vous devrez fournir les valeurs, mais vous pouvez utiliser la réflexion pour fournir les noms de param/types:

How can you get the names of method parameters?

Ainsi, la méthode sig changerait quelque chose comme:

public static void LogParameters(string[] methodNames, params object[] vals) 
{ } 

Ensuite, vous pouvez appliquer/supposer que chaque indice dans chaque décompte de collecte, de telle sorte que methodNames[0] a la valeur vals[0].

+0

Si possible, j'essaie d'éviter d'écrire les noms de paramètres dans l'appel LogParameters, afin de viser quelque chose comme: LogParamaters (GetMethodParams()); où GetMethodParams() retournera le tableau paramaters. Je ne suis pas trop dérangé par les frais généraux de boxe. –

+0

J'ai modifié ma réponse, mais comme d'autres l'ont dit, il existe des frameworks pour ajouter le code nécessaire en tant qu'étape du compilateur - ce qui signifie que vous n'avez pas besoin d'écrire beaucoup de code manuellement. –

+0

Bien sûr, le seul inconvénient avec PostSharp est qu'il n'est pas gratuit et vous avez encore besoin de modifier le code pour placer l'attribut. –

7

Si vous utilisez Postsharp vous pouvez simplement ajouter un attribut à la méthode que vous voulez vous connecter. Dans cet attribut, vous pouvez écrire le code de journalisation et également fournir les arguments dont vous avez besoin. Ceci est connu sous le nom de problèmes transversaux et AOP (programmation orientée aspect)

+0

+1. J'allais écrire quelque chose à propos de la réécriture automatique de la sortie CIL par le compilateur pour ajouter la journalisation, mais simplement utiliser un produit établi va probablement être plus facile. – stakx

+0

Aussi faire ce qui précède est actaully rapide et facile à faire avec elle. – aqwert

1

Bien params aider avec l'appel de journal, mais n'aidera pas les signatures de méthodes existantes. L'exploitation forestière au moyen d'un AOP framework pourrait être une approche plus productive?

4

Je ne suis pas sûr si l'API pour accéder à la pile d'appel fournit un moyen pour obtenir la liste des arguments.

Cependant, il existe des moyens pour injecter IL pour intercepter les appels de méthode et d'exécuter du code personnalisé.

La bibliothèque que j'utilise fréquemment est PostSharp par Gael Fraiteur, elle inclut une application qui exécute postbuild et injecte IL dans vos assemblys de sortie en fonction des Aspects que vous utilisez. Il existe des attributs avec lesquels vous pouvez décorer des assemblages, des types ou des méthodes individuelles. Par exemple:

[Serializable] 
public sealed class LoggingAttribute : OnMethodBoundaryAspect 
{ 
    public override void OnEntry(MethodExecutionArgs eventArgs) 
    { 
     Console.WriteLine("Entering {0} {1} {2}", 
          eventArgs.Method.ReflectedType.Name, 
          eventArgs.Method, 
          string.Join(", ", eventArgs.Arguments.ToArray())); 

     eventArgs.MethodExecutionTag = DateTime.Now.Ticks; 
    } 

    public override void OnExit(MethodExecutionArgs eventArgs) 
    { 
     long elapsedTicks = DateTime.Now.Ticks - (long) eventArgs.MethodExecutionTag; 
     TimeSpan ts = TimeSpan.FromTicks(elapsedTicks); 

     Console.WriteLine("Leaving {0} {1} after {2}ms", 
          eventArgs.Method.ReflectedType.Name, 
          eventArgs.Method, 
          ts.TotalMilliseconds); 
    } 
} 

Après cela, vous pouvez simplement décorer la méthode que vous voulez avec cet attribut:

[Logging] 
public void SomeMethod(String p1, String p2, int p3) 
{ 
    //.. 
} 
+0

('System.Diagnostics.StackTrace' /' System.Diagnostics.StackFrame' semble fournir uniquement le nom du fichier source et les informations de numéro de ligne etc., pas d'arguments réels.) – stakx

0

peuvent ne pas fonctionner dans certains scénarios, mais devrait vous aider à démarrer

:)
class Program 
{ 
    static void Main(string[] args) 
    { 
     M1("test"); 
     M2("test", "test2"); 
     M3("test", "test2", 1); 

     Console.ReadKey(); 
    } 

    static void M1(string p1) 
    { 
     Log(MethodBase.GetCurrentMethod()); 
    } 

    static void M2(string p1, string p2) 
    { 
     Log(MethodBase.GetCurrentMethod()); 
    } 

    static void M3(string p1, string p2, int p3) 
    { 
     Log(MethodBase.GetCurrentMethod()); 
    } 

    static void Log(MethodBase method) 
    { 
     Console.WriteLine("Method: {0}", method.Name); 
     foreach (ParameterInfo param in method.GetParameters()) 
     { 
      Console.WriteLine("ParameterName: {0}, ParameterType: {1}", param.Name, param.ParameterType.Name); 
     } 
    } 
} 
+0

après avoir corrigé pour ajouter l'espace de noms manquant System.Reflection il note qu'il fait ne pas dire quelles sont les valeurs. –

0

tant que vous savez quels types vous attendent pouvez les connecter dans une base de données SQL. Écrire une méthode qui effectue une vérification de type, et remplit ensuite la colonne DB appropriée avec la valeur de paramètre (argument). Si vous avez un type personnalisé, vous pouvez utiliser le nom du type et l'enregistrer en tant que chaîne dans sa propre colonne spéciale.

-Edit

Aussi, en utilisant la méthode d'extension MethodBase.Name, vous pouvez associer vos paramètres avec la méthode qui les a comme arguments comme mentionné dans un autre poste ci-dessous. Soyez un moyen pratique de garder une trace de toutes les méthodes utilisées, et avec quels arguments, et de quel type.

Est-ce vaguement une bonne idée? :)

Questions connexes