## Why is this an issue?

Both the `Enumerable.Max` extension method and the `SortedSet<T>.Max` property can be used to find the maximum value in a `SortedSet<T>`. However, `SortedSet<T>.Max` is much faster than `Enumerable.Max`. For small collections, the performance difference may be minor, but for large collections, it can be noticeable. The same applies for the `Min` property as well.

`Max` and `Min` in `SortedSet<T>` exploit the fact that the set is implemented via a `Red-Black tree`. The algorithm to find the `Max`/`Min` is "go left/right whenever possible". The operation has the time complexity of `O(h)` which becomes `O(ln(n))` due to the fact that the tree is balanced. This is much better than the `O(n)` time complexity of extension methods.

`Max` and `Min` in `ImmutableSortedSet<T>` exploits a tree augmentation technique, storing the `Min`, `Max` and `Count` values on each node of the data structure. The time complexity in this case is `O(1)` that is significantly better than `O(n)` of extension methods.

Applies to:

- SortedSet<T>.Max
- SortedSet<T>.Min
- ImmutableSortedSet<T>.Max
- ImmutableSortedSet<T>.Min
- ImmutableSortedSet<T>.Builder.Max
- ImmutableSortedSet<T>.Builder.Min

### What is the potential impact?

We measured a significant improvement both in execution time and memory allocation. For more details see the `Benchmarks` section from the `More info` tab.

## How to fix it

The `Min` and `Max` properties are defined on the following classes, and the extension method call can be replaced by calling the propery instead:

- `SortedSet<T>`
- `ImmutableSortedSet<T>`
- `ImmutableSortedSet<T>.Builder`

### Code examples

#### Noncompliant code example

    int GetMax(SortedSet<int> data) =>
        data.Max();

    int GetMin(SortedSet<int> data) =>
        data.Min();

#### Compliant solution

    int GetMax(SortedSet<int> data) =>
        data.Max;

    int GetMin(SortedSet<int> data) =>
        data.Min;

## Resources

### Documentation

- SortedSet<T>
- ImmutableSortedSet<T>
- ImmutableSortedSet<T>.Builder

### Benchmarks

Method | Runtime | Mean | Standard Deviation | Allocated
--- | --- | --- | --- | ---
MaxMethod | .NET 7.0 | 68,961.483 us | 499.6623 us | 248063 B
MaxProperty | .NET 7.0 | 4.638 us | 0.0634 us | -
MaxMethod | .NET Framework 4.6.2 | 85,827.359 us | 1,531.1611 us | 281259 B
MaxProperty | .NET Framework 4.6.2 | 67.682 us | 0.3757 us | 312919 B

#### Glossary

- Mean
- Standard Deviation
- Allocated

The results were generated by running the following snippet with BenchmarkDotNet:

    private SortedSet<string> data;

    [Params(1_000)]
    public int Iterations;

    [GlobalSetup]
    public void Setup() =>
        data = new SortedSet<string>(Enumerable.Range(0, Iterations).Select(x => Guid.NewGuid().ToString()));

    [Benchmark(Baseline = true)]
    public void MaxMethod()
    {
        for (var i = 0; i < Iterations; i++)
        {
            _ = data.Max();     // Max() extension method
        }
    }

    [Benchmark]
    public void MaxProperty()
    {
        for (var i = 0; i < Iterations; i++)
        {
            _ = data.Max;       // Max property
        }
    }

Hardware configuration:

    BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.19045.2846/22H2/2022Update)
    11th Gen Intel Core i7-11850H 2.50GHz, 1 CPU, 16 logical and 8 physical cores
      [Host]               : .NET Framework 4.8 (4.8.4614.0), X64 RyuJIT VectorSize=256
      .NET 7.0             : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
      .NET Framework 4.6.2 : .NET Framework 4.8 (4.8.4614.0), X64 RyuJIT VectorSize=256