2009-05-08 2 views
11

내가있어 코드 :이 냄새 나는 코드를 어떻게 리펙토링합니까? 이 같은 (로깅, 복사 및 붙여 넣기, 닷넷 3.5)

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."); 

는 좀 성능 프로파일 링을 수행하는 더 많은 개체 및 방법 주위에 유사한 코드를 포장해야합니다. 제 3 자 플러그인이나 소프트웨어 등을 사용할 수 없습니다.

나는이 모든 코드가 이러한 모든 로깅 코드를 호출하는 것과 같은 코드를 작성하지 않을 것입니다. 코딩 작업을 일부 제거하기 위해 어떻게 리팩터링 하시겠습니까?

내가 명확하지 않다면 의견에 질문을하면 명확하게하려고 노력할 것입니다.

도움 주셔서 감사합니다.

+1

이것이 Java 인 경우 AspectJ를 제안합니다. 닷넷에 상응하는 것이 있습니까? –

+0

.Net과 비슷한 점이 있지만 사용하지 못할 수도 있습니다. –

답변

19

메소드 포인터 인스턴스 (별칭 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."); 
} 

그런 다음 람다 식을 만들어 호출 할 수 있습니다. myResponse는 캡처 된 변수이므로이 Action이 실행될 때 myResponse가 채워지고이 범위에서 나중에 myResponse를 사용할 수 있습니다. 다음과 같이 MyTimer로 클래스가 구현

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

:

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

그건 꽤 섹시 해요. 아마도 가난한 전직 자바 동료들에게 지옥을 혼동시킬 것입니다. LOL –

+0

정말 멋지다 ... 나 혼란에 빠져있다. 정확히 거기에서 뭘하고 있니? :) – Jonas

+0

전화 샘플에서() 의미는 무엇입니까? 그냥 람다 블록을 아무것도 쓰지 않고 호출하는 것입니까? –

2

분명히 AOP 후보입니다. 우리는 이런 종류의 일에 PostSharp를 사용합니다. http://www.postsharp.org/

+0

로버트 감사합니다.하지만 지금 제 3 자 코드를 사용할 수 없습니다. –

+0

고용주에게 물어볼 가치가 있다고 말하고 싶습니다. 무료이며 사용자 측에서 별도의 작업이 필요하지 않습니다. 컴파일 단계에서 추가 코드를 추가하기 만하면 메소드에 속성을 추가하는 것처럼 간단합니다. 다른 방법이 없다면 로컬 복사본에서 코드를 사용하고 코드를 체크인하기 전에 모든 추적 코드가 제거되었는지 확인할 수 있습니다. 엉덩이에 통증이 있지만 문제가 해결됩니다. –

+0

글쎄, 나는 확실히 집에서 포스트 샤프로 놀기 시작할거야! :) –

6

는 단순 위해, 당신은 (내 머리 위로 떨어져)과 같이, 제네릭을 사용할 수

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

Func을 (S, T) S 메소드의 매개 변수 유형이며, T 반환 유형입니다.

5

은 내가 이런 식으로 사용할 수있는 타이머를 구현하고 생각

  • 이 정지 시계 인스턴스를 포함하고, 타이머를 식별하는 메시지 문자열
  • 생성자가 중지 감시를 시작하고 메시지 문자열
  • 을 기억합니다.
  • Dispose 메서드는 중지 감시를 중지하고 메시지 문자열과 경과 시간을 기록합니다.
+0

나는 이것을 좋아한다. 간단하고 이해하기 쉽습니다. +1 –

1

이 클래스를 작성하면 (Java를 사용하고 있습니다. 정확하게 번역하지 않는 몇 가지 물건)이있을 수 : 코드를 줄였다

다음
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."); 
    } 
} 

각 방법에 필요한 단지

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

을 할 수있는 PostSharp 라이브러리는 항상있다 aspect 지향 코드를 작성하십시오. 그것은 로깅과 스톱워치를 속성으로 할 수있게 해줍니다. 그것은 귀하의 방법에 사전 및 사후 코드를 포스트 컴파일 단계로 주입합니다.

또한, 당신은 당신이 시간에 원하는 코드를 래핑하는이 같은 일부 타이머/로거 정적 방법을 고려해 볼 수 있습니다/로그 :

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

당신은 로거에 대한 몇 가지 간단한 확장 방법과 구문 조금 청소기를 만들 수 , 이것은 이미 가지고있는 부품을 추가로 조립할 필요가 없으며 곧바로 플러그 할 수 있습니다. 그리고 코드 전체에서이 작업을 여러 번 반복하면 재사용 할 수 있습니다.

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(); 
    } 
} 

는 그냥

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

어떻게 당신이 당신의 모든 개체에 타이머 클래스를 상속에 대해 당신이 원래의 게시물에있는 코드의 교체에이 코드를 사용할 수 있을까?

0

이 경우 내가하고 싶은 것은 일회용 패턴을 사용하여 타이머를 구현하는 것입니다. 물론

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

당신이 (타이머에 인수를 전달할 수 있습니다

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. 
     } 
    } 

그런 다음이 같은 타이머를 사용 : 오류의 경우에는 올바른 정리 및 로깅을 보장 할 것 메소드 이름, 로거 등)을 사용하여 설정에서 발생하는 것을 사용자 정의하고 처리하십시오.