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:
Use pattern macthing to perform the check and retrieve the cast result.
if (x is Fruit) // Noncompliant
{
var f = (Fruit)x; // or x as Fruit
// ...
}
if (x is Fruit fruit)
{
// ...
}
is, as, typeof and casts | 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 |
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