156 votes

Comment pour intercepter un appel de méthode en c# ?

Pour une classe donnée, je voudrais avoir la fonctionnalité de traçage c'est à dire que je tiens à vous connecter à chaque appel de méthode (signature de la méthode et les valeurs de paramètre) et chaque méthode de sortie (juste la signature de la méthode).

Comment puis-je accomplir ceci en supposant que:

  • Je ne veux pas utiliser un 3ème partie AOP bibliothèques pour C#,
  • Je ne veux pas ajouter de code en double à toutes les méthodes que j'ai envie de trace,
  • Je ne veux pas changer l'API publique de la classe - les utilisateurs de la classe doivent être en mesure d'appeler toutes les méthodes exactement de la même manière.

Pour rendre la question plus concrète supposons qu'il y a 3 classes:

 public class Caller 
 {
     public static void Call() 
     {
         Traced traced = new Traced();
         traced.Method1();
         traced.Method2(); 
     }
 }

 public class Traced 
 {
     public void Method1(String name, Int32 value) { }

     public void Method2(Object object) { }
 }

 public class Logger
 {
     public static void LogStart(MethodInfo method, Object[] parameterValues);

     public static void LogEnd(MethodInfo method);
 }

Comment puis-je invoquer l' Enregistreur.LogStart et Enregistreur.LogEnd pour chaque appel de Method1 et Method2 sans modification de l' Appelant.Appel de la méthode, et sans ajouter l'appelle explicitement à Remonter.Method1 et Tracée.Method2?

Edit: Ce qui serait la solution si je me suis permis de modifier légèrement l'Appel de la méthode?

72voto

Jorge Córdoba Points 18919

C# n'est pas un AOP langage orienté. Il a certaines caractéristiques de l'AOP et vous pouvez émuler certains autres, mais faire de l'AOP avec C# est douloureux.

J'ai cherché des façons de faire exactement ce que tu voulais faire et je n'ai trouvé aucun moyen facile de le faire.

Comme je le comprends, c'est ce que vous voulez faire:

[Log()]
public void Method1(String name, Int32 value);

et pour ce faire, vous avez deux options principales

  1. Hériter de votre classe de MarshalByRefObject ou ContextBoundObject et de définir un attribut qui hérite de IMessageSink. Cet article est un bon exemple. Vous avez à considérer néanmoins que l'utilisation d'un MarshalByRefObject les performances vont diminuer comme l'enfer, et je veux dire, je parle d'un 10x performance perdu donc, bien réfléchir avant d'essayer.

  2. L'autre option consiste à injecter du code directement. Dans l'exécution, ce qui signifie que vous aurez à utiliser la réflexion pour "lire" chaque classe, de ses attributs et de les injecter le cas d'appel (et d'ailleurs je pense que vous ne pouvez pas utiliser la Réflexion.Émettre de la méthode que je crois la Réflexion.Émettre ne serait pas vous permettre d'insérer le nouveau code à l'intérieur d'une méthode déjà existante). Au moment de la conception, cela signifie la création d'une extension de la CLR compilateur que j'ai honnêtement aucune idée de comment c'est fait.

La dernière option est d'utiliser un Cio cadre. C'est peut-être pas la solution parfaite, comme la plupart des Cio cadres de travaux en définissant des points d'entrée qui permettent de méthodes pour être accroché mais, selon ce que vous voulez atteindre, qui pourrait être un juste aproximation.

49voto

Antoine Aubry Points 3276

La manière la plus simple de réaliser cela est probablement d'utiliser PostSharp . Il injecte du code dans vos méthodes en fonction des attributs que vous lui appliquez. Il vous permet de faire exactement ce que vous voulez.

Une autre option consiste à utiliser l’ API de profilage pour injecter du code dans la méthode, mais c’est vraiment hardcore.

7voto

Steen Points 3427

Si vous écrivez une classe - appelez traçage - qui implémente l’interface IDisposable, vous pouvez envelopper tous les corps de méthode dans un

Dans la classe de traçage, vous pourriez la poignée de la logique des traces dans la méthode de constructeur/Dispose, respectivement, dans la classe de traçage pour garder une trace de l’entrée et la sortie des méthodes. Tels que :

5voto

Gishu Points 59012

Jetez un oeil à cette - chose Assez lourd..http://msdn.microsoft.com/en-us/magazine/cc164165.aspx

Essentiel .net - don box avait un chapitre sur ce que vous devez appelé Interception. J'ai gratté un peu de ça ici (Désolé pour les couleurs de police, j'ai eu un thème sombre à l'époque...)http://madcoderspeak.blogspot.com/2005/09/essential-interception-using-contexts.html

5voto

Jay Points 1457

J’ai trouvé une manière différente qui peut être plus facile...

Déclarer une méthode InvokeMethod

Je définis ensuite mes méthodes comme suit

Maintenant, je peux avoir la vérification au moment de l’exécution sans l’injection de dépendance...

Aucuns pièges dans ne site  :)

J’espère que vous conviendrez que c’est moins poids puis un cadre AOP ou dérivant de MarshalByRefObject ou à l’aide de classes de proxy ou de communication à distance.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X