Hacking IDisposable: The Stopwatch Example
Tags: csharp, patterns, patternsilike, hackingidisposable
Published: 2022-02-20 22:20:35

> Provides a mechanism for releasing unmanaged resources.

This is the first sentence you can read about `IDisposable` interface in [the Microsoft documentation](https://docs.microsoft.com/en-us/dotnet/api/system.idisposable?view=net-6.0) - and it definitely should be the primary usage of it. However, the C# language is cool enough to have a special `using` statement that comes along when using objects that implement `IDisposable`. There is something elegant and compact about this language structure, which makes me really like it - that's why I use it even for places that it was not designed for. Like, for example, wrapping up the `Stopwatch`.

# Stopwatch

The [`Stopwatch`](https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.stopwatch?view=netframework-2.0) class was introduced in .NET Framework 2.0 and since then became a de facto standard for measuring code execution time. If you were ever interested in checking how long does it takes to run a specific part of your program, you've probably stumbled into it.

The basic usage pattern of a `Stopwatch` class is as follows:

```csharp
var stopwatch = new Stopwatch();
stopwatch.Start();

// Code which execution time we want to measure

stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);
```

There are a couple of caveats - static method `Stopwatch.StartNew()` can be used as a shortcut for creating `Stopwatch` instance and starting it at the same time. Also, the `Elapsed` property can be accessed without actually stopping the stopwatch first - it will keep on counting time.

So the structure is already there - we start the stopwatch, we execute the code we want to measure, we stop the stopwatch. Whenever and wherever you do it, the structure always looks similar to this. And since it's as simple as wrapping the "proper" code you want to measure with some init and teardown actions, the `using` statement might be a good fit.

# Disposable stopwatch

So lets start with defining a class implementing `IDisposable`.

```csharp
public class Timer : IDisposable
{
    private readonly Stopwatch _stopwatch;

    public Timer()
    {
        _stopwatch = Stopwatch.StartNew();
    }

    public void Dispose()
    {
        _stopwatch.Stop();
        Console.WriteLine(_stopwatch.Elapsed);
    }
}

// Usage example

using (new Timer())
{
    // Code which execution time we want to measure
}
```

This is functionally identical to the previous example and for me looks better already, however there are a couple of things we can do to make it more useful.

First of all, writing to the console output is not necessarily the only thing we want to do with the measured time span. Sometimes it might be, but sometimes we'd rather write it to file or to an external system, eventually ending up in some kind of monitoring platform.

So we could parametrize the `Timer` and allow its clients to decide what to do with the measured execution time.

```csharp
public class Timer : IDisposable
{
    private readonly Action<TimeSpan> _afterMeasuredAction;
    private readonly Stopwatch _stopwatch;

    public Timer(Action<TimeSpan> afterMeasuredAction)
    {
        _afterMeasuredAction = afterMeasuredAction ?? (_ => { });
        _stopwatch = Stopwatch.StartNew();
    }

    public void Dispose()
    {
        _stopwatch.Stop();
        _afterMeasuredAction.Invoke(_stopwatch.Elapsed);
    }
}

// Usage example

using (new Timer(measuredTime => Console.WriteLine(measuredTime)))
{
    // Code which execution time we want to measure
}
```

There's something I still don't like about this usage pattern. Maybe because we're newing up an object here that we don't really care about - not even assigning it to any variable. Effectively there's nothing wrong about it, cause what we really want is to create it and dispose automatically at the end of the `using` block. But if we don't need to do any other thing with this object - why do we need to know its type? Well, we don't - knowing that it implements `IDisposable` should be more than enough for us. So instead of newing up an instance of a specific type, I'd rather hide it with some method and directly return just an `IDisposable`.

```csharp
public class Measurement
{
    public static IDisposable Run(
        Action<TimeSpan> afterMeasuredAction = null) =>
            new Timer(afterMeasuredAction);

    private class Timer : IDisposable
    {
        private readonly Action<TimeSpan> _afterMeasuredAction;
        private readonly Stopwatch _stopwatch;

        public Timer(Action<TimeSpan> afterMeasuredAction)
        {
            _afterMeasuredAction = afterMeasuredAction ?? (_ => { });
            _stopwatch = Stopwatch.StartNew();
        }

        public void Dispose()
        {
            _stopwatch.Stop();
            _afterMeasuredAction.Invoke(_stopwatch.Elapsed);
        }
    }
}

// Usage example

using (Measurement.Run(measuredTime => Console.WriteLine(measuredTime))
{
    // Code which execution time we want to measure
}
```

One last thing I'd like to enhance a bit. Since `Measurement` is a very generic purpose class - probably for use in many places, as we usually want to measure execution time of multiple methods or algorithms within our code base - we'd normally define this action after measure (like `Console.WriteLine`) many times. To avoid that we can create a specific class that uses the generic one.

```csharp
public class LogMeasurement
{
    private readonly ILogger<LogMeasurement> _logger;

    public LogMeasurement(ILogger<LogMeasurement> logger)
    {
        _logger = logger;
    }

    public IDisposable Run() => Measurement.Run(
        timeSpan => _logger.LogTrace($"Measured time: {timeSpan}"));
}

// Usage example

using (_logMeasurement.Run())
{
    // Code which execution time we want to measure
}
```

Note that this time we have an instance `Run()` method instead of a static one as previously. The reason is that I'd probably want to inject this class in all the places I'd like to use it, so it's ready for usage in a dependency injection scenario. That's also why it has a constructor with its own dependencies injected. In other words we now have one class to gather everything needed to do whatever we want to do in our system with measured code execution time.

And if you sometimes want to do something else with it - you just define another similar class, which uses `Measurement.Run` with a different action, and inject it instead of the `LogMeasurement` one!

# Post Scriptum

This blog post is mostly about answering the "How to measure code execution time?" question. One thing I haven't and won't dig too deep into is an answer to "Where to measure it?" question. But just briefly - I do think that any code not related strictly to the domain of the class or method just adds noise and distraction. So adding some logging, monitoring or execution time measuring logic in-place with the domain code is not necessarily the best idea. I'd rather extract it to some kind of decorator class instead.

Also, sorry for the clickbaitish title - the provided example is not really hacking the interface in any way. But it can be considered a usage outside of the definition mentioned at the very beginning, so in this sense what we're really doing is exploring the undocumented ways of using it. Sounds hacky enough for me!

# Just code

[Hacking `IDisposable`: The Stopwatch Example on GitHub](https://github.com/jakubkwa/hacking-idisposable/tree/TheStopwatchExample/src/HackingDisposable.Measurements) + [Tests](https://github.com/jakubkwa/hacking-idisposable/tree/TheStopwatchExample/src/HackingDisposable.Measurements.Tests)