Why is this an issue?

In C#, the is type testing operator can be used to check if the run-time type of an object is compatible with a given type. If the object is not null, then the is operator performs a cast, and so performing another cast following the check result is redundant.

This can impact:

How to fix it

Use pattern macthing to perform the check and retrieve the cast result.

Code examples

Noncompliant code example

if (x is Fruit)  // Noncompliant
{
  var f = (Fruit)x; // or x as Fruit
  // ...
}

Compliant solution

if (x is Fruit fruit)
{
  // ...
}

Resources

Documentation

Benchmarks

Method Runtime Mean Standard Deviation

IsPattern_Class

.NET 9.0

176.48 ns

0.765 ns

IsWithCast_Class

.NET 9.0

246.12 ns

22.391 ns

IsPattern_Class

.NET Framework 4.8.1

325.11 ns

14.435 ns

IsWithCast_Class

.NET Framework 4.8.1

311.22 ns

11.145 ns

IsPattern_Interface

.NET 9.0

26.77 ns

1.123 ns

IsWithCast_Interface

.NET 9.0

26.45 ns

2.115 ns

IsPattern_Interface

.NET Framework 4.8.1

119.80 ns

5.411 ns

IsWithCast_Interface

.NET Framework 4.8.1

119.33 ns

4.380 ns

IsPattern_ValueType

.NET 9.0

22.58 ns

1.161 ns

IsWithCast_ValueType

.NET 9.0

19.41 ns

2.675 ns

IsPattern_ValueType

.NET Framework 4.8.1

39.66 ns

0.645 ns

IsWithCast_ValueType

.NET Framework 4.8.1

41.34 ns

0.462 ns

Glossary

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

private Random random = new Random(1);

private object ReturnSometimes<T>() where T : new() =>
    random.Next(2) switch
    {
        0 => new T(),
        1 => new object(),
    };

[BenchmarkCategory("ValueType"), Benchmark(Baseline = true)]
public int IsPattern_ValueType()
{
    var i = ReturnSometimes<int>();
    return i is int d
        ? d
        : default;
}

[BenchmarkCategory("ValueType"), Benchmark]
public int IsWithCast_ValueType()
{
    var i = ReturnSometimes<int>();
    return i is int
        ? (int)i
        : default;
}

[BenchmarkCategory("Class"), Benchmark(Baseline = true)]
public DuplicateCasts IsPattern_Class()
{
    var i = ReturnSometimes<DuplicateCasts>();
    return i is DuplicateCasts d
        ? d
        : default;
}

[BenchmarkCategory("Class"), Benchmark]
public DuplicateCasts IsWithCast_Class()
{
    var i = ReturnSometimes<DuplicateCasts>();
    return i is DuplicateCasts
        ? (DuplicateCasts)i
        : default;
}

[BenchmarkCategory("Interface"), Benchmark(Baseline = true)]
public IReadOnlyList<int> IsPattern_Interface()
{
    var i = ReturnSometimes<List<int>>();
    return i is IReadOnlyList<int> d
        ? d
        : default;
}

[BenchmarkCategory("Interface"), Benchmark]
public IReadOnlyList<int> IsWithCast_Interface()
{
    var i = ReturnSometimes<List<int>>();
    return i is IReadOnlyList<int>
        ? (IReadOnlyList<int>)i
        : default;
}

Hardware configuration:

BenchmarkDotNet v0.14.0, Windows 10 (10.0.19045.5247/22H2/2022Update)
Intel Core Ultra 7 165H, 1 CPU, 22 logical and 16 physical cores
  [Host]               : .NET Framework 4.8.1 (4.8.9282.0), X64 RyuJIT VectorSize=256
  .NET 9.0             : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX2
  .NET Framework 4.8.1 : .NET Framework 4.8.1 (4.8.9282.0), X64 RyuJIT VectorSize=256