rspec/rules/S2219/csharp/rule.adoc

108 lines
3.1 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:
* ``++expr is SomeType++`` or ``++expr.GetType() == typeof(SomeType)++`` if the type is known at compile time,
* ``++typeInstance.IsInstanceOfType(expr)++`` if the type is calculated during runtime.
If runtime calculated ``++Type++``s need to be compared:
* ``++typeInstance1.IsAssignableFrom(typeInstance2)++``.
Depending on whether the type is returned by a ``++GetType()++`` or ``++typeof()++`` call, the ``++IsAssignableFrom()++`` and ``++IsInstanceOfType()++`` might be simplified. Similarly, if the type is ``++sealed++``, the type comparison with ``++==++`` can be converted to an ``++is++`` call. Simplifying the calls also make ``++null++`` checking unnecessary because both ``++is++`` and ``++IsInstanceOfType++`` performs it already.
Finally, utilizing the most concise language constructs for type checking makes the code more readable, so
* ``++expr as T != null++`` checks should be simplified to ``++expr is T++``, and
* ``++expr is T++`` should be converted to ``++expr != null++``, when ``++expr++`` is of type ``++T++``.
== 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 ``++GetType++`` on an object of ``++Nullable<T>++`` type returns the underlying generic type parameter ``++T++``, thus a comparison with ``++typeof(Nullable<T>)++`` can't be simplified to use the ``++is++`` operator, which doesn't make difference between ``++T++`` and ``++T?++``.
----
int? i = 42;
bool condition = i.GetType() == typeof(int?); // false;
condition = i is int?; // true
----
No issue is reported on the following expressions:
* ``++expr is T++`` when either operand of the ``++is++`` operator is a value type. In that case CS0183 or CS0184 reports
* ``++expr is object++``, as this is a common and efficient pattern to do null checks
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
include::message.adoc[]
'''
== Comments And Links
(visible only on this page)
include::comments-and-links.adoc[]
endif::env-github,rspecator-view[]