Fred Tingaud 16f6c0aecf
Inline adoc when include has no additional value (#1940)
Inline adoc files when they are included exactly once.

Also fix language tags because this inlining gives us better information
on what language the code is written in.
2023-05-25 14:18:12 +02:00

123 lines
3.9 KiB
Plaintext
Raw Permalink 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.

== Why is this an issue?
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
[source,csharp]
----
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
[source,csharp]
----
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?++``.
[source,csharp]
----
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)
=== Message
Use [the "is" operator|the "IsInstanceOfType()" method|a "null" check] instead.
'''
== Comments And Links
(visible only on this page)
=== on 24 May 2019, 16:47:10 Andrei Epure wrote:
\[~nicolas.harraudeau] there's an interesting remark from a user (issue https://github.com/SonarSource/sonar-dotnet/issues/2424[#2424]) who says that it's actually better to perform ``++expr is object++`` rather than ``++expr != null++`` because of performance implications
=== on 24 May 2019, 17:15:38 Nicolas Harraudeau wrote:
\[~andrei.epure] It looks to me like this is a tradeof between readability and performance. Using ``++expr is object++`` to do a null check is more performant but less intuitive than ``++expr != null++``. We could simply accept both ``++expr is object++`` and ``++expr != null++``, explaining in the description the difference. What do you think?
include::../comments-and-links.adoc[]
endif::env-github,rspecator-view[]