rspec/rules/S4015/csharp/rule.adoc

107 lines
2.9 KiB
Plaintext
Raw Normal View History

== Why is this an issue?
2023-06-13 12:23:03 +02:00
Decreasing the https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers[accessibility level] of an inherited method that is not https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/override[overridable] to https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/private[private] will shadow the name of the base method and can lead to confusion.
2021-04-28 16:49:39 +02:00
2023-06-13 12:23:03 +02:00
[source,csharp]
----
public class Base
{
public void SomeMethod(int count) { }
}
public class Derived : Base
{
private void SomeMethod(int count) { } // Noncompliant
}
2021-04-28 16:49:39 +02:00
2023-06-13 12:23:03 +02:00
class Program
{
public void DoWork()
{
var derived = new Derived();
derived.SomeMethod(42); // Base.SomeMethod is accessed here
}
}
----
2023-06-13 12:23:03 +02:00
Another potential problem is the case of a class deriving from `Derived` and accessing `SomeMethod`. In this scenario, the method accessed will instead be the `Base` implementation, which might not be what was expected.
2021-04-28 16:49:39 +02:00
2022-02-04 17:28:24 +01:00
[source,csharp]
2021-04-28 16:49:39 +02:00
----
2023-06-13 12:23:03 +02:00
public class Base
2021-04-28 16:49:39 +02:00
{
public void SomeMethod(int count) { }
2023-06-13 12:23:03 +02:00
}
public class Derived : Base
{
2021-04-28 16:49:39 +02:00
private void SomeMethod(int count) { } // Noncompliant
}
2023-06-13 12:23:03 +02:00
public class SecondDerived : Derived
{
public void DoWork()
{
SomeMethod(42); // Base.SomeMethod is accessed here
}
}
----
2023-06-13 12:23:03 +02:00
One way to mitigate this, is by sealing the `Derived` class by using the https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/sealed[sealed] modifier, thus preventing inheritance from this point on.
2021-04-28 16:49:39 +02:00
2022-02-04 17:28:24 +01:00
[source,csharp]
2021-04-28 16:49:39 +02:00
----
2023-06-13 12:23:03 +02:00
public class Base
2021-04-28 16:49:39 +02:00
{
public void SomeMethod(int count) { }
2023-06-13 12:23:03 +02:00
}
public sealed class Derived : Base
{
private void SomeMethod(int count) { } // Compliant: class is marked as sealed
2021-04-28 16:49:39 +02:00
}
----
2023-06-13 12:23:03 +02:00
Another way to mitigate this, is by having the `Derived` implementation match the https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers[accessibility] modifier of the `Base` implementation of `SomeMethod`. From a caller's perspective, this is closer to the expected behavior.
2023-06-13 12:23:03 +02:00
[source,csharp]
----
using System;
2023-06-13 12:23:03 +02:00
namespace MyLibrary
{
public class Base
{
public void SomeMethod(int count) { }
}
public class Derived : Base
{
public void SomeMethod(int count) { } // Compliant: same accessibility as Base.SomeMethod
}
public class Program
{
public void DoWork()
{
var derived = new Derived();
derived.SomeMethod(42); // Derived.SomeMethod is called
}
}
}
----
2023-06-13 12:23:03 +02:00
Last but not least, consider using a different name for the `Derived` method, thus completely eliminating any confusion caused by the naming collision.
2023-06-13 12:23:03 +02:00
[source,csharp]
----
public class Base
{
public void SomeMethod(int count) { }
}
public class Derived : Base
{
private void SomeOtherMethod(int count) { } // Compliant
}
----
2023-06-13 12:23:03 +02:00
include::../resources.adoc[]
2023-06-13 12:23:03 +02:00
include::../rspecator.adoc[]