2010-01-14 5 views
11

On peut énumérer les appelés types de paramètres de la méthode/informations comme ceci:comment énumèrent passé paramètres méthode

private void SomeMethod(int thisValue, string thatValue) 
{ 
    StackTrace stackTrace = new StackTrace(); 
    foreach (ParameterInfo pInfo in stackTrace.GetFrame(0).GetMethod().GetParameters()) 
    { 
    string name = pInfo.Name; 
    string type = pInfo.GetType().ToString(); 
    } 
} 

Mais est-il possible d'obtenir l'objet réel de chaque paramètre?

EDIT: Mon but est d'énumérer tous les paramètres et d'obtenir leurs valeurs. LINQ expressions, on peut obtenir la valeur du paramètre comme ceci:

private void SomeMethod(int thisValue, string thatValue) 
{ 
    object valueOfThis = GetParameterValue(() => thisValue); 
    object valueOfThat = GetParameterValue(() => thatValue); 
} 
private object GetParameterValue<T>(Expression<Func<T>> expr) 
{ 
    var body = ((MemberExpression)expr.Body); 
    return ((FieldInfo)body.Member).GetValue(((ConstantExpression)body.Expression).Value); 
} 

Mais ce que je voudrais faire est quelque chose comme:

foreach (fooObject o in thisMethod.GetParameterObjects()) 
{ 
    object someValue = GetParameterValue(() => fooObject); 
} 

et ont ainsi une méthode générique pour la collecte de tous les paramètres et leurs valeurs.

+0

Essayez-vous de créer une trace de pile contenant les valeurs de paramètre réelles? –

+1

Uhm, les instances de paramètres réelles sont là dans la méthode ... –

+1

@Mark: ma pensée aussi, mais voyant qu'il est évident qu'il cherche quelque chose de plus général, quelque chose qui vous permettrait d'obtenir les valeurs de n'importe quelle trame de pile (Je devine ...) –

Répondre

9

MISE À JOUR:

On dirait que je "overcomplicated" la réponse initiale en essayant de tout expliquer. Voici la version courte de la réponse.

private static void SomeMethod(int thisValue, string thatValue) 
{ 
    IEnumerable<object> parameters = GetParameters(() => SomeMethod(thisValue, thatValue)); 
    foreach (var p in parameters) 
     Console.WriteLine(p); 
} 
private static IEnumerable<object> GetParameters(Expression<Action> expr) 
{ 
    var body = (MethodCallExpression)expr.Body; 
    foreach (MemberExpression a in body.Arguments) 
    { 
     var test = ((FieldInfo)a.Member).GetValue(((ConstantExpression)a.Expression).Value); 
     yield return test; 
    } 
} 

Et voici la version longue avec quelques explications. En fait, si vous utilisez des arbres d'expression, vous n'avez pas besoin d'être dans une méthode pour énumérer ses paramètres. Notez que si vous utilisez des arbres d'expression, votre code dépend beaucoup d'une expression passée à la méthode. J'ai montré un en utilisant des constantes et un en utilisant des variables. Mais bien sûr, il peut y avoir plus de scénarios. Vous pouvez refactoriser ce code pour utiliser une seule méthode dans les deux cas, mais j'ai décidé que cela illustre mieux le problème de cette façon.

+0

Merci pour la réponse. Cependant, je cherchais quelque chose qui pourrait être mis dans SomeMethod() pour le rendre générique. L'exemple fourni vous oblige à appeler le code personnalisé avant SomeMethod(). –

+0

Non, vous n'avez pas besoin d'appeler quoi que ce soit avant SomeMethod. Prenez le code marqué "seconde approche" (sautez simplement la déclaration des variables et l'initialisation) et collez-le à la méthode. Vous obtiendrez l'énumération des paramètres à l'intérieur de la méthode. Je voulais juste souligner que vous pouvez le faire de n'importe où, pas nécessairement du corps de la méthode. –

+0

Si vous devez explicitement lister les paramètres dans le code source, pourquoi utiliser 'GetParameters'? Cela fera: 'object [] params = nouvel objet [] {thisValue, thatValue}; ' –

1

Bon, alors voici l'affaire.

Vous ne pouvez pas faire cela, pas à partir d'un langage géré. Je ne vois pas comment quelqu'un vous permettrait de prendre le contrôle du cadre de la pile. Et d'une manière c'est ce que tu veux. Parce que vous avez besoin de l'information pour obtenir les valeurs. Maintenant que l'exécution le sait, elle contient toutes les informations, mais vous ne pouvez pas faire d'hypothèses sur la manière de créer un cadre de pile, car vous n'êtes pas censé le faire.

Ergo, il n'y a qu'une seule façon d'y arriver. L'API de profilage

Je finis par here. Dans les fonctions de l'API de profilage. Je parie qu'il y a un moyen de faire cela qui vous permet de creuser dans les valeurs des paramètres en invoquant une classe non gérée à partir du code managé.

Maintenant, je ne ferais pas cela parce qu'il y a d'excellents outils de profilage là-bas, JetBrains dotTrace pour en nommer un et avec IntelliTrace dans VS2010 tous ces maux de tête vont tout simplement disparaître ... IntelliTrace vous permettra de faire du débogage. L'autre façon évidente de le faire est totalement foobar, mais cela pourrait être amusant à expérimenter, cela peut toujours être fait de cette façon, mais je ne mettrais jamais ce code dans un environnement de production.

// compile with unsafe 
unsafe 
{ 
    var p = stackalloc int[1]; 
    var baseAddr = p - sizeof(int); 
} 

Maintenant, vous ne pouvez pas écrire à baseAddr mais vous devriez être autorisé à le lire. La partie la plus délicate est de donner un sens aux cadres de pile et cela doit être fait avec la convention d'appel et que vous devez savoir avec certitude. Here's un run down de ce genre de choses et c'est fastcall. Avec cette information et les objets ParameterInfo, vous devriez être en mesure de parcourir les arguments. Puisque vous allez travailler avec des pointeurs bruts, vous devrez les transformer en objets gérés, et il existe un class pour cela.

Et voilà, c'est fou!

Un gros avertissement bien que, ce que vous trouverez en marchant dans la pile, ne sera pas ce que vous attendez. Les arguments peuvent être placés dans des registres et les registres ne sont pas accessibles depuis le code managé.

1

Vous pouvez utiliser MethodInfo.GetCurrentMethod().GetParameters() pour obtenir une liste de paramètres de méthode. Mais il est impossible d'obtenir leurs valeurs par réflexion.

+1

@Mehdi. Oui, la méthode GetParameters() était déjà couverte dans ma question, merci. –

Questions connexes