-
Notifications
You must be signed in to change notification settings - Fork 0
/
CodeTimer.cs
103 lines (87 loc) · 2.56 KB
/
CodeTimer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
using System;
using System.Diagnostics;
#if !NET20
using System.Linq.Expressions;
#endif
#if !NET20 && !NET35
using System.Threading.Tasks;
#endif
namespace UtiliDude
{
public class CodeTimer : IDisposable
{
private readonly Stopwatch _stopwatch;
private readonly string _name;
private static readonly object _lock = new object();
private CodeTimer(string name)
{
_name = name.IsNullOrWhiteSpace()
? throw new ArgumentException($"'{nameof(name)}' cannot be null or whitespace.", nameof(name))
: name;
_stopwatch = Stopwatch.StartNew();
#if DEBUG
Debug.WriteLine($"Starting {_name} timer.");
#if !NET20
ExecuteWithLock(() => Debug.Indent());
#endif
#endif
}
public static IDisposable Start(string name) => new CodeTimer(name);
public void Stop()
{
if (_stopwatch.IsRunning)
{
_stopwatch.Stop();
#if DEBUG
#if !NET20
ExecuteWithLock(() => Debug.Unindent());
#endif
Debug.WriteLine($" ←← {_name} took {_stopwatch.ElapsedMilliseconds}ms.");
#endif
}
}
public void Dispose() => Stop();
// Time for synchronous Actions
public static void Time(Action action) => TimeInternal(action, action.Method.Name);
#if !NET20 && !NET35
// Time for Expression-based Actions (not available in .NET 2.0 and .NET 3.5)
public static void Time(Expression<Action> actionExpression)
{
if (actionExpression.Body is MethodCallExpression methodCall)
{
string methodName = methodCall.Method.Name;
Action actionToInvoke = actionExpression.Compile();
TimeInternal(actionToInvoke, methodName);
}
else
{
throw new ArgumentException("The expression must be a method call.");
}
}
// Time for async Func<Task> (not available in .NET 2.0 and .NET 3.5)
public static async Task TimeAsync(Func<Task> action)
{
string methodName = action.Method.Name;
await TimeInternal(action, methodName);
}
private static async Task TimeInternal(Func<Task> action, string methodName)
{
using (Start(methodName))
{
await action();
}
}
#endif
private static void TimeInternal(Action action, string methodName)
{
using (Start(methodName))
{
action();
}
}
private void ExecuteWithLock(Action action)
{
lock (_lock) { action(); }
}
}
}