rspec/rules/S2219/csharp/rule.adoc
Alban Auzeill 2c306d110e Fix code block ambiguity with old header style
Ensure blank line before list and clean the one leading space
2020-06-30 17:16:12 +02:00

92 lines
3.0 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

To check the type of an object there are several options:
* <code>expr is SomeType</code> or <code>expr.GetType() == typeof(SomeType)</code> if the type is known at compile time,
* <code>typeInstance.IsInstanceOfType(expr)</code> if the type is calculated during runtime.
If runtime calculated <code>Type</code>s need to be compared:
* <code>typeInstance1.IsAssignableFrom(typeInstance2)</code>.
Depending on whether the type is returned by a <code>GetType()</code> or <code>typeof()</code> call, the <code>IsAssignableFrom()</code> and <code>IsInstanceOfType()</code> might be simplified. Similarly, if the type is <code>sealed</code>, the type comparison with <code>==</code> can be converted to an <code>is</code> call. Simplifying the calls also make <code>null</code> checking unnecessary because both <code>is</code> and <code>IsInstanceOfType</code> performs it already.
Finally, utilizing the most concise language constructs for type checking makes the code more readable, so
* <code>expr as T != null</code> checks should be simplified to <code>expr is T</code>, and
* <code>expr is T</code> should be converted to <code>expr != null</code>, when <code>expr</code> is of type <code>T</code>.
== Noncompliant Code Example
----
class Fruit { }
sealed class Apple : Fruit { }
class Program
{
static void Main()
{
var apple = new Apple();
var b = apple != null && apple.GetType() == typeof (Apple); // Noncompliant
b = typeof(Apple).IsInstanceOfType(apple); // Noncompliant
if (apple != null)
{
b = typeof(Apple).IsAssignableFrom(apple.GetType()); // Noncompliant
}
var appleType = typeof (Apple);
if (apple != null)
{
b = appleType.IsAssignableFrom(apple.GetType()); // Noncompliant
}
Fruit f = apple;
if (f as Apple != null) // Noncompliant
{
}
if (apple is Apple) // Noncompliant
{
}
}
}
----
== Compliant Solution
----
class Fruit { }
sealed class Apple : Fruit { }
class Program
{
static void Main()
{
var apple = new Apple();
var b = apple is Apple;
b = apple is Apple;
b = apple is Apple;
var appleType = typeof(Apple);
b = appleType.IsInstanceOfType(apple);
Fruit f = apple;
if (f is Apple)
{
}
if (apple != null)
{
}
}
}
----
== Exceptions
Calling <code>GetType</code> on an object of <code>Nullable<T></code> type returns the underlying generic type parameter <code>T</code>, thus a comparison with <code>typeof(Nullable<T>)</code> can't be simplified to use the <code>is</code> operator, which doesn't make difference between <code>T</code> and <code>T?</code>.
----
int? i = 42;
bool condition = i.GetType() == typeof(int?); // false;
condition = i is int?; // true
----
No issue is reported on the following expressions:
* <code>expr is T</code> when either operand of the <code>is</code> operator is a value type. In that case CS0183 or CS0184 reports
* <code>expr is object</code>, as this is a common and efficient pattern to do null checks