---
title: "Enum.Equals - Performance analysis"
description: "Did you know that you can spend 100x times longer depending how you compare your enums?\n\nOf course we are speaking here in terms of nanoseconds but this story is much more then just numbers. We'll also talk about boxing and unboxing. So let's dive right into it."
updated: 2022-01-11
tags: ["Equals", "C#", "Enums", "Performance"]
canonical: "https://steven-giesel.com/blogPost/0a8eec1a-84a2-4c2e-a083-8c7ccb372a41/enumequals-performance-analysis"
---

# Enum.Equals - Performance analysis

Imagine we have this very enum:
```csharp
public enum Color
{
    Red = 0,
    Green = 1,
}
```

Nothing really fancy but for us it is enough. We have multiple ways of comparing if two instances of an enum are the same. But before I dive into some explanation I'll show you the results upfront with the benchmark code:

```csharp
public class Benchmark
{
    private readonly Color _colorRed = Color.Red;
    private readonly Color _colorGreen = Color.Green;

    [Benchmark(Baseline = true)]
    public bool ObjectEquals() => Equals(_colorRed, _colorGreen);

    [Benchmark]
    public bool EnumEquals() => Enum.Equals(_colorRed, _colorGreen);

    [Benchmark]
    public bool InstanceEquals() => _colorRed.Equals(_colorGreen);

    [Benchmark]
    public bool ComparisonOperator() => _colorRed == _colorGreen;
}
```

We have 4 options to compare:
 * `object.Equals`
 * `Enum.Equals`
 * Call `Equals` from on the instance method
 * Use the comparison operator `==`

Now bring in the results:
```no-class
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1348 (21H1/May2021Update)
Intel Core i7-7820HQ CPU 2.90GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
.NET SDK=6.0.101
  [Host]     : .NET 6.0.1 (6.0.121.56705), X64 RyuJIT
  DefaultJob : .NET 6.0.1 (6.0.121.56705), X64 RyuJIT


|             Method |      Mean |     Error |    StdDev |    Median | Ratio | RatioSD |
|------------------- |----------:|----------:|----------:|----------:|------:|--------:|
|       ObjectEquals | 9.1618 ns | 0.2113 ns | 0.1765 ns | 9.1957 ns | 1.000 |    0.00 |
|         EnumEquals | 9.1438 ns | 0.1075 ns | 0.0839 ns | 9.1245 ns | 0.997 |    0.02 |
|     InstanceEquals | 9.9292 ns | 0.2370 ns | 0.5858 ns | 9.7626 ns | 1.086 |    0.10 |
| ComparisonOperator | 0.0445 ns | 0.0353 ns | 0.0571 ns | 0.0250 ns | 0.008 |    0.01 |
```

What the duck! Basically only the comparison operator takes only 1/100 of the time as the other variations!

Now let's find out why!

## Boxing and unboxing
Now the first two approaches have the same runtime (considering the error-rate). Why is that?  Well `EnumEquals` and `ObjectEquals` are the same. Even our IDE will give us a hint here:

![EnumEquals](https://linkdotnetblog.azureedge.net/blog/20221101_EnumEquals/EnumHint.webp)

We can see that the `Enum` qualifier is redundant. But why is that. Well here we go:

![Enum object equals](https://linkdotnetblog.azureedge.net/blog/20221101_EnumEquals/EnumObjectEqualsHint.webp)

When we hover over `Enum.Equals` as well as `Equals` we get the hint that this is invoked from `object`. So what does `object.Equals` do here? It is quite simple:
```csharp
public static bool Equals(object? objA, object? objB)
{
    if (objA == objB)
    {
        return true;
    }
    if (objA == null || objB == null)
    {
        return false;
    }
    return objA.Equals(objB);
}
```

Hold on the first line looks like our last approach, which is the fastest! So did I manipulate the test because my enums are not the same and therefore the runtime is way longer. **No**.
Even if we would this:
```csharp
[Benchmark]
public bool InstanceEqualsWhenTheSame() => _colorRed.Equals(_colorRed);
``` 
We'd get this:
```no-class
|                    Method |     Mean |     Error |    StdDev |
|-------------------------- |---------:|----------:|----------:|
| InstanceEqualsWhenTheSame | 9.821 ns | 0.1284 ns | 0.1138 ns |
```

The same runtime! So we see that all approaches with `Equals` are the same and only the last one is somehow different.
Let's have a look at the IL-code.

This `Equals(_colorRed, _colorGreen);` as well as this `_colorRed.Equals(_colorGreen);` will *roughly* translate to the same IL-code:
```no-class
IL_0005: ldloc.0
IL_0006: box C/Color
IL_000b: ldloc.1
IL_000c: box C/Color
IL_0011: call bool [System.Private.CoreLib]System.Object::Equals(object, object)
IL_0016: pop
```
<sup>The shown example above is from `Equals(_colorRed, _colorGreen);`</sup>

Now `IL_0006: box C/Color` and `IL_000c: box C/Color` are interesting! We have to box our enums!

How does it look for our `==` case?
```no-class
IL_002b: ldloc.0
IL_002c: ldloc.1
IL_002d: ceq
IL_002f: stloc.2
```
Yes you see right. There is no boxing. Just a simple equality comparison [`ceq`](https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.ceq?view=net-6.0).
By the way if you want to play around on your own: [sharplab.io](https://sharplab.io/#v2:EYLgtghglgdgNAFxFANnAJiA1AHwAIBMAjALABQeAzAASHUDC1A3udW7TQKYwCuYDAexQCATuRZl21AEqd01ALzUADHFbsA4iM7dF1ImrIBfcurZVaAFmoBZABQBKZmamDhI6gH0AxkNGz5JXo/EQA6AIBuFylg9y9fdy0dGD1Y0VCk7iiyaPZctgBRAEceCBQAZzsfEIC4eJDMmAds13Zq9wDQ4tKKqoTRRub86gA3CA9gPXb/OUUlaZFGlvYTYyA==)

> Boxing is the process of converting a value type to the type object or to any interface type implemented by this value type. When the common language runtime (CLR) boxes a value type, it wraps the value inside a System.Object instance and stores it on the managed heap. Unboxing extracts the value type from the object. Boxing is implicit; unboxing is explicit.

<sup>From the official [Microsoft documentation]( https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/boxing-and-unboxing)

Boxing a value type into a reference type costs a bit time. And this is exactly why it is so more expensive. If you want to know more about boxing / unboxing I'd suggest to read the link above.

If you want to have another example of boxing/unboxing [here you go](https://steven-giesel.com/blogPost/94d8b54b-c30d-4bdb-ab95-96769b418e6d). Here I discussed boxing and unboxing in string interpolation.

The repository can be found: [here](https://github.com/linkdotnet/BlogExamples/tree/main/EnumEqualsPerformance)
Central repository with a lot of samples discussed in this blog can be found [https://github.com/linkdotnet/BlogExamples](here)