## Why is this an issue?

Both the `List.TrueForAll` method and the `IEnumerable.All` method can be used to check if all list elements satisfy a given condition in a collection. However, `List.TrueForAll` can be faster than `IEnumerable.All` for `List` objects. The performance difference may be minor for small collections, but for large collections, it can be noticeable.

It is important to enable this rule with caution, as performance outcomes can vary significantly across different runtimes. Notably, the performance improvements in .NET 9 have brought `All` closer to the performance of collection-specific `TrueForAll` methods in most scenarios.

Applies to

- List
- Array
- ImmutableList
- ImmutableList.Builder

### What is the potential impact?

We measured at least 4x improvement both in execution time. For more details see the `Benchmarks` section from the `More info` tab.

## How to fix it

The `TrueForAll` method is defined on the collection class, and it has the same signature as the `All` extension method. The method can be replaced in place.

### Code examples

#### Noncompliant code example

    Public Function AreAllEven(data As List(Of Integer)) As Boolean
        Return data.All(Function(x) x Mod 2 = 0)
    End Function

    Public Function AreAllEven(data As Integer()) As Boolean
        Return data.All(Function(x) x Mod 2 = 0)
    End Function

#### Compliant solution

    Public Function AreAllEven(data As List(Of Integer)) As Boolean
        Return data.TrueForAll(Function(x) x Mod 2 = 0)
    End Function

    Public Function AreAllEven(data As Integer()) As Boolean
        Return Array.TrueForAll(data, Function(x) x Mod 2 = 0)
    End Function

## Resources

### Documentation

- Microsoft Learn - List<T>.TrueForAll(Predicate<T>)
- Microsoft Learn - Array.TrueForAll<T>(T[], Predicate<T>)
- Microsoft Learn - ImmutableList<T>.TrueForAll(Predicate<T>)
- Microsoft Learn - ImmutableList<T>.Builder.TrueForAll(Predicate<T>)
- Microsoft Learn - Enumerable.All<TSource>

### Benchmarks

Method | Runtime | Categories | Mean | Standard Deviation | Allocated
--- | --- | --- | --- | --- | ---
ArrayAll | .NET 8.0 | Array | 109.25 μs | 1.767 μs | 32 B
ArrayTrueForAll | .NET 8.0 | Array | 45.01 μs | 0.547 μs | -
ArrayAll | .NET 9.0 | Array | 22.28 μs | 0.254 μs | -
ArrayTrueForAll | .NET 9.0 | Array | 37.60 μs | 0.382 μs | -
ArrayAll | .NET Framework 4.8.1 | Array | 495.90 μs | 4.342 μs | 40 B
ArrayTrueForAll | .NET Framework 4.8.1 | Array | 164.52 μs | 2.030 μs | -
ImmutableListAll | .NET 8.0 | ImmutableList<T> | 940.29 μs | 5.600 μs | 72 B
ImmutableListTrueForAll | .NET 8.0 | ImmutableList<T> | 679.46 μs | 2.371 μs | -
ImmutableListAll | .NET 9.0 | ImmutableList<T> | 922.43 μs | 14.564 μs | 72 B
ImmutableListTrueForAll | .NET 9.0 | ImmutableList<T> | 692.31 μs | 8.897 μs | -
ImmutableListAll | .NET Framework 4.8.1 | ImmutableList<T> | 4,578.72 μs | 77.920 μs | 128 B
ImmutableListTrueForAll | .NET Framework 4.8.1 | ImmutableList<T> | 4,393.49 μs | 122.061 μs | -
ImmutableListBuilderAll | .NET 8.0 | ImmutableList<T>.Builder | 970.45 μs | 13.598 μs | 73 B
ImmutableListBuilderTrueForAll | .NET 8.0 | ImmutableList<T>.Builder | 687.82 μs | 6.142 μs | -
ImmutableListBuilderAll | .NET 9.0 | ImmutableList<T>.Builder | 981.17 μs | 12.966 μs | 72 B
ImmutableListBuilderTrueForAll | .NET 9.0 | ImmutableList<T>.Builder | 710.19 μs | 16.195 μs | -
ImmutableListBuilderAll | .NET Framework 4.8.1 | ImmutableList<T>.Builder | 4,780.50 μs | 43.282 μs | 128 B
ImmutableListBuilderTrueForAll | .NET Framework 4.8.1 | ImmutableList<T>.Builder | 4,493.82 μs | 76.530 μs | -
ListAll | .NET 8.0 | List<T> | 151.12 μs | 2.028 μs | 40 B
ListTrueForAll | .NET 8.0 | List<T> | 58.03 μs | 0.493 μs | -
ListAll | .NET 9.0 | List<T> | 22.14 μs | 0.327 μs | -
ListTrueForAll | .NET 9.0 | List<T> | 46.01 μs | 0.327 μs | -
ListAll | .NET Framework 4.8.1 | List<T> | 619.86 μs | 6.037 μs | 48 B
ListTrueForAll | .NET Framework 4.8.1 | List<T> | 208.49 μs | 2.340 μs | -

#### Glossary

- Mean
- Standard Deviation
- Allocated

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

    // Explicitly cache the delegates to avoid allocations inside the benchmark.
    private readonly static Func<int, bool> ConditionFunc = static x => x == Math.Abs(x);
    private readonly static Predicate<int> ConditionPredicate = static x => x == Math.Abs(x);

    private List<int> list;
    private ImmutableList<int> immutableList;
    private ImmutableList<int>.Builder immutableListBuilder;
    private int[] array;

    [Params(100_000)]
    public int N { get; set; }

    [GlobalSetup]
    public void GlobalSetup()
    {
        list = Enumerable.Range(0, N).Select(x => N - x).ToList();
        immutableList = ImmutableList.CreateRange(list);
        immutableListBuilder = ImmutableList.CreateBuilder<int>();
        immutableListBuilder.AddRange(list);
        array = list.ToArray();
    }

    [BenchmarkCategory("List<T>"), Benchmark]
    public bool ListAll() =>
        list.All(ConditionFunc);

    [BenchmarkCategory("List<T>"), Benchmark(Baseline = true)]
    public bool ListTrueForAll() =>
        list.TrueForAll(ConditionPredicate);

    [BenchmarkCategory("ImmutableList<T>"), Benchmark(Baseline = true)]
    public bool ImmutableListAll() =>
        immutableList.All(ConditionFunc);

    [BenchmarkCategory("ImmutableList<T>"), Benchmark]
    public bool ImmutableListTrueForAll() =>
        immutableList.TrueForAll(ConditionPredicate);

    [BenchmarkCategory("ImmutableList<T>.Builder"), Benchmark(Baseline = true)]
    public bool ImmutableListBuilderAll() =>
        immutableListBuilder.All(ConditionFunc);

    [BenchmarkCategory("ImmutableList<T>.Builder"), Benchmark]
    public bool ImmutableListBuilderTrueForAll() =>
        immutableListBuilder.TrueForAll(ConditionPredicate);

    [BenchmarkCategory("Array"), Benchmark(Baseline = true)]
    public bool ArrayAll() =>
        array.All(ConditionFunc);

    [BenchmarkCategory("Array"), Benchmark]
    public bool ArrayTrueForAll() =>
        Array.TrueForAll(array, ConditionPredicate);

Hardware configuration:

    BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.4317/23H2/2023Update/SunValley3)
    11th Gen Intel Core i7-11850H 2.50GHz, 1 CPU, 16 logical and 8 physical cores
      [Host]               : .NET Framework 4.8.1 (4.8.9277.0), X64 RyuJIT VectorSize=256
      .NET 8.0             : .NET 8.0.10 (8.0.1024.46610), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
      .NET 9.0             : .NET 9.0.0 (9.0.24.47305), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
      .NET Framework 4.8.1 : .NET Framework 4.8.1 (4.8.9277.0), X64 RyuJIT VectorSize=256