S2219 — Runtime type checking should be simplified

Language
C#
Type
Code smell
Severity
Minor
Tags
clumsy

Why is this an issue?

In .NET, several forms can check an object’s runtime type. Some are equivalent in a particular context, but one form can make the question being asked clearer.

Choose the replacement based on what is known at that point in the code:

How to fix it

The type is known in the code

Use is instead of casting only to test whether the cast works.


object fruit = new Apple();

bool isApple = fruit as Apple != null; // Noncompliant
isApple = fruit is Apple;              // Compliant

The same applies to GetType() checks when the target type is sealed. A sealed type cannot have subclasses, so both checks have the same result.


sealed class Apple { }

object fruit = new Apple();

bool isApple = fruit.GetType() == typeof(Apple);  // Noncompliant
isApple = fruit is Apple;                         // Compliant

isApple = typeof(Apple).IsInstanceOfType(fruit);  // Noncompliant
isApple = fruit is Apple;                         // Compliant

The type is known only at runtime

When the expected type is stored in a Type variable, is cannot be used. Call IsInstanceOfType() with the object itself instead of comparing runtime types.


Type expectedType = GetExpectedType();
object value = GetValue();

bool matches = expectedType.IsAssignableFrom(value.GetType());  // Noncompliant
matches = expectedType.IsInstanceOfType(value);                 // Compliant

The expression already has the target type

If the compiler already knows an expression is an Apple, checking value is Apple only tests whether it is null.


Apple apple = GetApple();

if (apple is Apple) // Noncompliant
{
}

if (apple != null)  // Compliant
{
}

Both is and IsInstanceOfType() return false for null, so these replacements do not need an extra null check.

Exceptions

Cautions


int? value = 42;

bool isNullableInt = value.GetType() == typeof(int?); // false
isNullableInt = value is int?;                        // true

↑ Back to top