2009-05-08 28 views
11

Tôi đã có mã như thế này:Làm thế nào bạn sẽ refactor mã này có mùi? (Logging, Copy và Paste, Net 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."); 

tôi cần phải quấn mã tương tự xung quanh rất nhiều đối tượng và phương pháp của họ để làm một số profiling hiệu suất. Tôi không được phép sử dụng plugin hoặc phần mềm của bên thứ ba, v.v.

Tôi thực sự không viết mã giống như vậy xung quanh tất cả các phương thức này gọi tất cả mã đăng nhập này. Làm thế nào bạn sẽ refactor này để loại bỏ một số nỗ lực mã hóa của tôi?

Nếu tôi không rõ ràng, hãy đặt câu hỏi trong phần nhận xét và tôi sẽ cố làm rõ.

Cảm ơn bạn đã trợ giúp !!

+1

Nếu đây là Java, tôi khuyên bạn nên sử dụng AspectJ. Có tương đương với .Net không? –

+0

Có gì đó tương tự với .Net, nhưng có lẽ tôi sẽ không được phép sử dụng nó. –

Trả lời

19

Bạn có thể cấu trúc lại mã để chấp nhận trường hợp con trỏ phương thức (aka 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."); 
} 

Sau đó, bạn có thể gọi bằng cách tạo biểu thức lambda. Vì myResponse là một biến bị bắt, nó sẽ được điền khi Hành động này được chạy và myResponse sẽ có sẵn để sử dụng sau này trong phạm vi này.

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

Điều đó khá gợi cảm. Có lẽ sẽ gây nhầm lẫn cho các đồng nghiệp cũ của tôi. lol –

+0

Đó là khá mát mẻ ... confuses địa ngục ra khỏi tôi ... chính xác những gì bạn đang làm ở đó? :) – Jonas

+0

() có nghĩa là gì trong mẫu cuộc gọi của bạn? Liệu nó có nghĩa là bạn đang gọi khối lambda mà không truyền bất cứ thứ gì vào nó? –

2

Chắc chắn là một ứng cử viên cho AOP. Chúng tôi sử dụng PostSharp cho loại điều này. http://www.postsharp.org/

+0

Cảm ơn Robert, nhưng tôi không được phép sử dụng mã của bên thứ 3 ngay bây giờ. –

+0

Tôi muốn nói rằng nó đáng để hỏi nhà tuyển dụng của bạn. Nó hoàn toàn miễn phí và không yêu cầu thêm bất cứ điều gì vào cuối của người dùng. Nó chỉ thêm mã bổ sung vào trong bước biên dịch, và nó làm cho việc này đơn giản như thêm thuộc tính vào một phương thức. Nếu không có gì khác, bạn chỉ có thể sử dụng nó trên bản sao cục bộ của mình và đảm bảo tất cả các dấu vết được xóa trước khi kiểm tra mã. Đau ở mông, nhưng nó sẽ giải quyết vấn đề của bạn. –

+0

Vâng, tôi chắc chắn sẽ bắt đầu chơi với postsharp ở nhà! :) –

6

Để đơn giản vì lợi ích, bạn có thể sử dụng Generics, như vậy (ra khỏi đỉnh đầu của tôi):

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

Func (S, T) trong đó S là kiểu tham số của phương pháp này, và T là kiểu trả về.

5

Tôi nghĩ rằng tôi thực hiện một lớp đếm thời gian mà có thể được sử dụng như thế này:

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

Lớp MyTimer được thực hiện như sau:

  • Có một trường hợp dừng lại xem, và một chuỗi tin nhắn xác định bộ hẹn giờ
  • Hàm khởi tạo bắt đầu đồng hồ dừng và nhớ chuỗi tin nhắn
  • Phương pháp Vứt bỏ dừng đồng hồ dừng và ghi lại chuỗi tin nhắn và thời gian đã trôi qua
+0

Tôi thích điều này. Đơn giản và dễ hiểu. +1 –

1

Nếu bạn viết một lớp như thế này (tôi đang sử dụng Java; có thể có một số nội dung mà không dịch chính xác):

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

Sau đó, bạn đã giảm mã bạn cần trong mỗi phương pháp để chỉ

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

Luôn luôn có những thư viện PostSharp cho phép bạn làm mã hướng-khía cạnh. Nó cho phép bạn thực hiện ghi nhật ký và đồng hồ bấm giờ dưới dạng thuộc tính, điều này thật tuyệt. Nó sẽ tiêm trước và sau mã trong phương pháp của bạn như là một bước sau biên dịch.

Hơn nữa, bạn có thể xem xét một số phương pháp tĩnh timer/logger như thế này để quấn mã bạn muốn thời gian/log:

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

Bạn có thể thực hiện cú pháp một chút bụi với một số phương pháp mở rộng đơn giản trên Logger , điều này đòi hỏi không có hội đồng bổ sung sau đó những gì bạn đã có và bạn có thể cắm nó ngay lập tức. Và nó có thể tái sử dụng, nếu bạn định làm điều này nhiều lần trong suốt mã của bạn.

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

sau đó bạn chỉ có thể sử dụng mã này thay thế đoạn code mà bạn có trong bài gốc của bạn

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

Làm thế nào về bạn kế thừa lớp hẹn giờ trên tất cả các đối tượng của bạn?

0

Điều tôi thích làm trong những trường hợp này là triển khai bộ hẹn giờ của tôi bằng mẫu Dùng một lần; bạn sẽ được đảm bảo dọn dẹp đúng và khai thác gỗ trong trường hợp có sai sót:

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

Sau đó, bạn sử dụng bộ đếm thời gian như thế này:

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

Tất nhiên bạn có thể vượt qua args để bộ đếm thời gian (tên phương thức, nhật ký, vv) để tùy chỉnh những gì đang diễn ra trong quá trình thiết lập và xử lý

Các vấn đề liên quan