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:
- Use
value is Twhen the expected type is written in the source code. - Use
type.IsInstanceOfType(value)when the expected type is known only at runtime. - Use a null check when the expression is already known to have the target type.
- Use
value.GetType() == typeof(T)when the exact runtime type matters. Otherwise, use the form that directly expresses the intended type check.
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
- Keep
value is objectwhen it is used as a null check. It is an established idiom and is not reported by this rule.
Cautions
- Do not replace a
GetType()comparison withiswhen the target isNullable<T>. A nullable value with a value boxes asT, so the checks can have different results.
int? value = 42;
bool isNullableInt = value.GetType() == typeof(int?); // false
isNullableInt = value is int?; // true