2008-10-05 14 views

Respuesta

4

La mejor manera de lograr este tipo de cosas es mediante el uso de la interceptación, Hay un par de maneras de hacer esto, sin embargo todos ellos tienden a ser un poco invasivo. Uno sería derivar todos sus objetos de ContextBoundObject. Here es un ejemplo del uso de este tipo de enfoque. El otro enfoque sería utilizar una de las bibliotecas de AOP existentes para lograr esto. Algo como DynamicProxy del Castle Project es el núcleo de muchos de estos. Aquí hay algunos enlaces: Spring.Net PostSharp Cecil

Probablemente hay varios otros, y sé Castle Windsor y Ninject ambos proporcionan capacidades de AOP en la parte superior de la funcionalidad del COI.

Una vez AOP está en su lugar sólo tendría que escribir una clase interceptor que escribir la información sobre el método llama a log4net.

En realidad no me sorprendería que uno de los marcos de AOP le daría ese tipo de funcionalidad fuera de la caja.

3

Se puede usar un post-compilador como Postsharp. El ejemplo del sitio web habla sobre la configuración de un rastreador para ingresar/salir de un método, que es muy similar a lo que desea.

4

no estoy seguro de lo que son sus necesidades reales, pero aquí es una opción de bajo alquiler. No es exactamente "automático", pero se puede usar StackTrace de pelar la información que está buscando en una manera que no exigiría pasar argumentos - similar a la sugerencia sobre intercepción de ckramer:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

using System.Diagnostics; 

namespace TracingSample 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      DoSomething(); 
     } 

     static void DoSomething() 
     { 
      LogEnter(); 

      Console.WriteLine("Executing DoSomething"); 

      LogExit(); 
     } 

     static void LogEnter() 
     { 
      StackTrace trace = new StackTrace(); 
      if (trace.FrameCount > 1) 
      { 
       string ns = trace.GetFrame(1).GetMethod().DeclaringType.Namespace; 
       string typeName = trace.GetFrame(1).GetMethod().DeclaringType.Name; 
       Console.WriteLine("Entering {0}.{1}.{2}", ns, typeName, trace.GetFrame(1).GetMethod().Name); 
      } 
     } 

     static void LogExit() 
     { 
      StackTrace trace = new StackTrace(); 
      if (trace.FrameCount > 1) 
      { 
       string ns = trace.GetFrame(1).GetMethod().DeclaringType.Namespace; 
       string typeName = trace.GetFrame(1).GetMethod().DeclaringType.Name; 
       Console.WriteLine("Exiting {0}.{1}.{2}", ns, typeName, trace.GetFrame(1).GetMethod().Name); 
      } 
     } 
    } 
} 

Se puede combinar algo así como el ejemplo anterior con la herencia, el uso de un miembro del público no virtual en el tipo base para indicar el método de acción, a continuación, llamar a un miembro virtual de hacer realidad la obra:

public abstract class BaseType 
{ 
    public void SomeFunction() 
    { 

     LogEnter(); 
     DoSomeFunction(); 
     LogExit(); 
    } 

    public abstract void DoSomeFunction(); 
} 

public class SubType : BaseType 
{ 
    public override void DoSomeFunction() 
    { 
     // Implementation of SomeFunction logic here... 
    } 
} 

una vez más - no hay mucho "automático "sobre esto, pero funcionaría de forma limitada si no necesitaras instrumentación en cada método invoc ación.

Espero que esto ayude.

+1

Este código va bien con este código para capturar el parámetro Valor de http://stackoverflow.com/a/6928253/1267778. Entonces tengo algo como logService.LogEnter (arg1, arg2, arg3). Buena cosa – parliament

0

Puede usar el marco de código abierto CInject en CodePlex que tiene un LogInjector para marcar la entrada y salida de una llamada a un método.

O puede seguir los pasos mencionados en este artículo en Intercepting Method Calls using IL y crear su propio interceptor utilizando clases Reflection.Emit en C#.

0

Funciones

Para ampliar la respuesta de Jared, evitando la repetición de códigos e incluyendo options for arguments:

private static void LogEnterExit(bool isEnter = true, params object[] args) 
{ 
    StackTrace trace = new StackTrace(true); // need `true` for getting file and line info 
    if (trace.FrameCount > 2) 
    { 
     string ns = trace.GetFrame(2).GetMethod().DeclaringType.Namespace; 
     string typeName = trace.GetFrame(2).GetMethod().DeclaringType.Name; 
     string args_string = args.Length == 0 ? "" : "\narguments: [" + args.Aggregate((current, next) => string.Format("{0},{1};", current, next))+"]"; 
     Console.WriteLine("{0} {1}.{2}.{3}{4}", isEnter ? "Entering" : "Exiting", ns, typeName, trace.GetFrame(2).GetMethod().Name, args_string); 
    } 
} 

static void LogEnter(params object[] args) 
{ 
    LogEnterExit(true, args); 
} 

static void LogExit(params object[] args) 
{ 
    LogEnterExit(false, args); 
} 

Uso

static void DoSomething(string arg1) 
{ 
    LogEnter(arg1); 
    Console.WriteLine("Executing DoSomething"); 
    LogExit(); 
} 

salida

En la consola, este sería el salida si DoSomething se ejecutó con "blah" como arg1

Entering Program.DoSomething 
arguments: [blah] 
Executing DoSomething 
Exiting Program.DoSomething 
Cuestiones relacionadas