108 lines
3.1 KiB
Plaintext
108 lines
3.1 KiB
Plaintext
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[]
|