109 lines
3.9 KiB
Plaintext
109 lines
3.9 KiB
Plaintext
== Why is this an issue?
|
|
|
|
One of the possible ways of performing https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast[type-testing] is via the https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/is[is operator]: `food is Pizza`.
|
|
|
|
The `is` operator is often used before a direct https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression[cast] to the target type, as a more flexible and powerful alternative to the https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator[as operator], especially when used to perform https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#type-testing-with-pattern-matching[pattern matching].
|
|
|
|
[source,csharp]
|
|
----
|
|
if (food is Pizza pizza)
|
|
----
|
|
|
|
There's no valid reason to test `this` with `is`. The only plausible explanation for such a test is that you're executing code in a parent class conditionally based on the kind of child class `this` is.
|
|
|
|
[source,csharp]
|
|
----
|
|
public class Food
|
|
{
|
|
public void DoSomething()
|
|
{
|
|
if (this is Pizza) // Noncompliant
|
|
{
|
|
// Code specific to Pizza...
|
|
}
|
|
}
|
|
}
|
|
----
|
|
|
|
However, code that's specific to a child class should be _in_ that child class, not in the parent.
|
|
|
|
== How to fix it
|
|
|
|
One way is to take advantage of the https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/tutorials/oop[object-orientation] of C# and use https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/polymorphism[polymorphism].
|
|
|
|
* Make the method https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/virtual[virtual], if it is not already. That will allow derived classes to perform https://en.wikipedia.org/wiki/Method_overriding[method overriding].
|
|
* Move the code to the right level of the type hierarchy.
|
|
* Use https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/base[base] to call the method on the base class that has been overridden.
|
|
|
|
For example, when simple method polymorphism is not enough because it is necessary to reuse multiple sections of the parent method, the https://en.wikipedia.org/wiki/Template_method_pattern[Template method pattern] might help.
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,csharp,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
public class Food
|
|
{
|
|
public void DoSomething()
|
|
{
|
|
// Code shared by all Food...
|
|
if (this is Pizza) // Noncompliant
|
|
{
|
|
// Code specific to Pizza...
|
|
}
|
|
}
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,csharp,diff-id=1,diff-type=compliant]
|
|
----
|
|
public class Food
|
|
{
|
|
public virtual void DoSomething()
|
|
{
|
|
// Code shared by all Food...
|
|
}
|
|
}
|
|
|
|
public class Pizza : Food
|
|
{
|
|
public override void DoSomething()
|
|
{
|
|
base.DoSomething();
|
|
// Code specific to Pizza...
|
|
}
|
|
}
|
|
----
|
|
|
|
== Resources
|
|
|
|
=== Documentation
|
|
|
|
* https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast[Type-testing operators and cast expressions - is, as, typeof and casts]
|
|
* https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/pattern-matching[Pattern matching overview]
|
|
* https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/tutorials/oop[Object-Oriented programming (C#)]
|
|
* https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/polymorphism[Polymorphism]
|
|
* https://en.wikipedia.org/wiki/Template_method_pattern[Template method pattern]
|
|
* https://en.wikipedia.org/wiki/Method_overriding[Method overriding]
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Message
|
|
|
|
Offload the code that's conditional on this "is" test to the appropriate subclass and remove the test.
|
|
|
|
|
|
'''
|
|
== Comments And Links
|
|
(visible only on this page)
|
|
|
|
include::../comments-and-links.adoc[]
|
|
endif::env-github,rspecator-view[]
|