2009-05-08 13 views
11

Tengo la siguiente manera:¿Cómo podría refactorizar este código maloliente? (Registro, copiar y pegar, Net 3.5) Código

Logger logger = new Logger(); 
System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); 
logger.LogInformation("Calling SomeObject.SomeMethod at " + DateTime.Now.ToString()); 
stopWatch.Start(); 
// This is the method I'm interested in. 
SomeResponse response = someObject.SomeMethod(someParam); 
stopWatch.Stop(); 
logger.LogInformation("SomeObject.SomeMethod returned at " + DateTime.Now.ToString()); 
logger.LogInformation("SomeObject.SomeMethod took " + stopWatch.ElapsedMilliseconds + " milliseconds."); 

necesito para envolver un código similar alrededor de un lote más objetos y sus métodos para hacer algo de perfiles de rendimiento. No tengo permiso para usar complementos de terceros o software, etc.

Realmente preferiría no escribir este mismo código en todas estas llamadas a este método, todo este código de registro. ¿Cómo podría refactorizar esto para eliminar parte de mi esfuerzo de codificación?

Si no estoy siendo muy claro, por favor haga preguntas en los comentarios e intentaré aclarar.

¡Gracias por cualquier ayuda!

+1

Si esto fuera Java, sugeriría AspectJ. ¿Hay un equivalente para .Net? –

+0

Hay algo similar para .Net, pero probablemente no podría usarlo. –

Respuesta

19

Puede refactorizar el código para aceptar una instancia de puntero a método (también conocido como System.Action).

public void CallWithLogTiming (Action theAction) 
{ 
    Logger logger = new Logger(); 
    System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); 
    logger.LogInformation("Calling SomeObject.SomeMethod at " + DateTime.Now.ToString()); 
    stopWatch.Start(); 

// This is the method I'm interested in. 
    theAction(); 

    stopWatch.Stop(); 
    logger.LogInformation("SomeObject.SomeMethod returned at " + DateTime.Now.ToString()); 
    logger.LogInformation("SomeObject.SomeMethod took " + stopWatch.ElapsedMilliseconds + " milliseconds."); 
} 

Luego puede llamarlo creando una expresión lambda. Como myResponse es una variable capturada, se completará cuando se ejecute esta acción y myResponse estará disponible para su uso más adelante en este ámbito.

SomeResponse myResponse = null; 
CallWithLogTiming(() => myResponse = someObject.SomeMethod(someParam)); 
+1

Eso es muy sexy. Probablemente confundiré a mis pobres colegas ex Java. lol –

+0

Eso es genial ... me saca de quicio ... ¿qué estás haciendo exactamente allí? :) – Jonas

+0

¿Qué significa() en la muestra de su llamada? ¿Simplemente significa que estás llamando al bloque lambda sin pasarle nada? –

2

Definitivamente un candidato para AOP. Usamos PostSharp para este tipo de cosas. http://www.postsharp.org/

+0

Gracias Robert, pero no estoy autorizado a usar código de terceros en este momento. –

+0

Yo diría que vale la pena preguntarle a su empleador. Es gratis y no requiere nada adicional para el usuario. Simplemente agrega código adicional durante el paso de compilación. Y hace que este tipo de cosas sea tan simple como agregar un atributo a un método. Si nada más, puede usarlo en su propia copia local y asegurarse de que se eliminen todos los rastros antes de registrar el código. Dolor en el culo, pero resolverá tu problema. –

+0

¡Bien, ciertamente voy a empezar a jugar con postsharp en casa! :) –

6

Para simplificar, se puede usar genéricos, como tal (de la parte superior de mi cabeza):

public T MyLogMethod<T,S>(Func<S, T> someFunction, S someParameter) {} 

Func (S, T) donde S es el tipo de parámetro del método, y T es el tipo de devolución.

5

creo que implementar una clase de temporizador que puede ser utilizado como esto:

void test() 
{ 
    foo(); 
    //timer for the following statements 
    using (new MyTimer("Some method")) 
    { 
    bar(); 
    } 
    baz(); 
} 

La clase MyTimer se implementa de la siguiente manera:

  • contiene una instancia cronómetro, y una cadena de mensaje que identifica el temporizador
  • El constructor inicia el cronómetro y recuerda la cadena del mensaje
  • El método Dispose detiene el cronómetro, y registra la cadena del mensaje y el tiempo de ellapsed
+0

Me gusta esto. Simple y comprensible +1 –

1

Si se escribe una clase como esta (estoy usando Java; podría haber algunas cosas que no se traduce exactamente):

public class myProfiler { 
    final String method; 
    final Logger logger = new Logger(); 
    final System.Diagnostics.Stopwatch stopWatch = new Stopwatch(); 
    public myProfiler(method) {this.method = method}; 
    public void Start() { 
     logger.LogInformation("Calling " + method + " at " + DateTime.Now.ToString()); 
     stopWatch.Start();  
    } 
    public void Stop() { 
     stopWatch.Stop(); 
     logger.LogInformation(method + " returned at " + DateTime.Now.ToString()); 
     logger.LogInformation(method + " took " + stopWatch.ElapsedMilliseconds + " milliseconds."); 
    } 
} 

Luego que haya reducido el código que necesita en cada método para simplemente

myProfiler profiler = new myProfiler("SomeObject.SomeMethod"); 
profiler.Start(); 
... 
profiler.Stop(); 
2

Siempre hay la biblioteca PostSharp que le permite hacer código orientado a aspectos Te permite hacer el registro y el cronómetro como un atributo, lo cual es genial. Inyectará código pre y post en su método como un paso posterior a la compilación.

Además, es posible considerar algunos métodos estáticos temporizador/logger como este para envolver el código que desee el tiempo/log:

Timer.LogExecutionTime("SomeObject.SomeMethod",() => 
{ 
    Logger.LogBeforeAndAfter("SomeObject.SomeMethod",() => 
    { 
     SomeResponse response = someObject.SomeMethod(someParam); 
    } 
}); 
2

usted podría hacer la sintaxis un poco más limpio con algunos métodos de extensión simples en Logger , esto no requiere ensambles adicionales, entonces lo que ya tiene y puede conectarlo de inmediato. Y es reutilizable, si va a hacer esto un montón de veces a lo largo de su código.

public static class LoggerExtentions 
{ 
    public static void StartTimerLogInformation(this Logger logger, Stopwatch stopWatch, string method) 
    { 
     stopWatch.Reset(); 
     stopWatch.Start(); 
     logger.LogInformation(string.Format("Calling {0} at {1}", method, DateTime.Now.ToString())); 
    }   

    public static void StopTimerLogInformation(this Logger logger, Stopwatch stopWatch, string method) 
    { 
     stopWatch.Stop(); 
     logger.LogInformation(string.Format("{0} returned at {1}", method, DateTime.Now.ToString())); 
     logger.LogInformation(string.Format("{0} took {1} milliseconds", method, stopWatch.ElapsedMilliseconds)); 
     stopWatch.Reset(); 
    } 
} 

entonces usted podría utilizar este código en sustitución del código que usted tiene en su puesto original

Logger logger = new Logger(); 
Stopwatch stopWatch = new Stopwatch(); 
logger.StartTimerLogInformation(stopWatch, "SomeObject.SomeMethod"); 
SomeResponse response = someObject.SomeMethod(someParam); 
logger.StopTimerLogInformation(stopWatch, "SomeObject.SomeMethod"); 
0

¿Qué se hereda la clase temporizador en todos sus objetos?

0

Lo que me gusta hacer en estos casos es implementar mis temporizadores usando el patrón Desechable; se le garantiza la limpieza y el registro correcto en caso de un error:

public class Timer : IDisposable 
    { 
     Logger logger = new Logger(); 
     Stopwatch stopWatch = new Stopwatch(); 

     public Timer() 
     { 
      calledFunc = CalledFunc; 
      logger.LogInformation("Calling SomeObject.SomeMethod at " + 
       DateTime.Now.ToString()); 
      stopWatch.Start(); 
     } 

     // Dispose() calls Dispose(true) 
     public void Dispose() 
     { 
      Dispose(true); 
      GC.SuppressFinalize(this); 
     } 
     // NOTE: Leave out the finalizer altogether if this class doesn't 
     // own unmanaged resources itself, but leave the other methods 
     // exactly as they are. 
     ~Timer() 
     { 
      // Finalizer calls Dispose(false) 
      Dispose(false); 
     } 
     // The bulk of the clean-up code is implemented in Dispose(bool) 
     protected virtual void Dispose(bool disposing) 
     { 
      if (disposing) 
      { 
       // free managed resources 
       stopWatch.Stop(); 
       logger.LogInformation("SomeObject.SomeMethod returned at " + 
        DateTime.Now.ToString()); 
       logger.LogInformation("SomeObject.SomeMethod took " + 
        stopWatch.ElapsedMilliseconds + " milliseconds."); 
      } 
      // free native resources if there are any. 
     } 
    } 

A continuación, utiliza el temporizador de la siguiente manera:

using (var t = new Timer()) 
{ 
    // your code 
} 

Por supuesto que puede pasar argumentos al temporizador (nombre del método, registrador, etc.) para personalizar lo que está sucediendo en la configuración y eliminar

Cuestiones relacionadas