rspec/rules/S3060/csharp/rule.adoc

110 lines
3.9 KiB
Plaintext
Raw Normal View History

== 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`.
2020-06-30 12:48:39 +02:00
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].
2020-06-30 12:48:39 +02:00
2022-02-04 17:28:24 +01:00
[source,csharp]
2020-06-30 12:48:39 +02:00
----
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
2020-06-30 12:48:39 +02:00
{
public void DoSomething()
{
if (this is Pizza) // Noncompliant
{
// Code specific to Pizza...
}
2020-06-30 12:48:39 +02:00
}
}
----
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].
2023-06-07 15:41:34 +02:00
* 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.
2023-06-07 15:41:34 +02:00
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[]