Modify rule S3260: Update rule to include file access modifier (#1798)
This commit is contained in:
parent
32593aad3b
commit
8632f42ef1
57
rules/S3260/csharp/code.adoc
Normal file
57
rules/S3260/csharp/code.adoc
Normal file
@ -0,0 +1,57 @@
|
||||
=== Code examples
|
||||
|
||||
==== Noncompliant code example
|
||||
|
||||
[source,csharp,diff-id=1,diff-type=noncompliant]
|
||||
----
|
||||
private class MyClass // Noncompliant
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
private record MyRecord // Noncompliant
|
||||
{
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
[source,csharp,diff-id=2,diff-type=noncompliant]
|
||||
----
|
||||
file class MyClass // Noncompliant
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
file record MyRecord // Noncompliant
|
||||
{
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
==== Compliant solution
|
||||
|
||||
[source,csharp,diff-id=1,diff-type=compliant]
|
||||
----
|
||||
private sealed class MyClass
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
private sealed record MyRecord
|
||||
{
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
[source,csharp,diff-id=2,diff-type=compliant]
|
||||
----
|
||||
file sealed class MyClass
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
file sealed record MyRecord
|
||||
{
|
||||
// ...
|
||||
}
|
||||
----
|
3
rules/S3260/csharp/how.adoc
Normal file
3
rules/S3260/csharp/how.adoc
Normal file
@ -0,0 +1,3 @@
|
||||
== How to fix it
|
||||
|
||||
The code can be improved by adding the `sealed` keyword in front of the `class` or `record` types that have no inheritors.
|
67
rules/S3260/csharp/impact.adoc
Normal file
67
rules/S3260/csharp/impact.adoc
Normal file
@ -0,0 +1,67 @@
|
||||
=== What is the potential impact?
|
||||
|
||||
We measured at least 4x improvement in the execution time by running the following snippet with https://github.com/dotnet/BenchmarkDotNet[BenchmarkDotNet].
|
||||
|
||||
[source,csharp]
|
||||
----
|
||||
[Params(1_000_000)]
|
||||
public int Iterations { get; set; }
|
||||
|
||||
private readonly UnsealedClass unsealedType = new UnsealedClass();
|
||||
private readonly SealedClass sealedType = new SealedClass();
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
public void UnsealedType()
|
||||
{
|
||||
for (int i = 0; i < Iterations; i++)
|
||||
{
|
||||
unsealedType.DoNothing();
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void SealedType()
|
||||
{
|
||||
for (int i = 0; i < Iterations; i++)
|
||||
{
|
||||
sealedType.DoNothing();
|
||||
}
|
||||
}
|
||||
|
||||
private class BaseType
|
||||
{
|
||||
public virtual void DoNothing() { }
|
||||
}
|
||||
|
||||
private class UnsealedClass : BaseType
|
||||
{
|
||||
public override void DoNothing() { }
|
||||
}
|
||||
|
||||
private sealed class SealedClass : BaseType
|
||||
{
|
||||
public override void DoNothing() { }
|
||||
}
|
||||
----
|
||||
|
||||
[options="header"]
|
||||
|===
|
||||
|Method | Runtime | Iterations | Mean | Error | StdDev | Ratio
|
||||
| UnsealedType | .NET 5.0 | 1000000 | 918.7 us | 12.09 us | 10.72 us | 1.00
|
||||
| SealedType | .NET 5.0 | 1000000 | 231.2 us | 3.61 us | 3.20 us | 0.25
|
||||
| UnsealedType | .NET 6.0 | 1000000 | 867.9 us | 6.38 us | 5.65 us | 1.00
|
||||
| SealedType | .NET 6.0 | 1000000 | 218.4 us | 0.71 us | 0.59 us | 0.25
|
||||
| UnsealedType | .NET 7.0 | 1000000 | 1,074.5 us | 3.55 us | 3.15 us | 1.00
|
||||
| SealedType | .NET 7.0 | 1000000 | 216.1 us | 1.28 us | 1.19 us | 0.20
|
||||
|===
|
||||
|
||||
Configuration used for running the benchmarks:
|
||||
```
|
||||
BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.19045.2846/22H2/2022Update)
|
||||
12th Gen Intel Core i7-12800H, 1 CPU, 20 logical and 14 physical cores
|
||||
.NET SDK=7.0.203
|
||||
[Host] : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
|
||||
.NET 5.0 : .NET 5.0.17 (5.0.1722.21314), X64 RyuJIT AVX2
|
||||
.NET 6.0 : .NET 6.0.16 (6.0.1623.17311), X64 RyuJIT AVX2
|
||||
.NET 7.0 : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
|
||||
```
|
10
rules/S3260/csharp/resources.adoc
Normal file
10
rules/S3260/csharp/resources.adoc
Normal file
@ -0,0 +1,10 @@
|
||||
== Resources
|
||||
|
||||
=== Documentation
|
||||
|
||||
* https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/sealed[The `sealed` keyword]
|
||||
|
||||
=== Articles & blog posts
|
||||
|
||||
* https://code-maze.com/improve-performance-sealed-classes-dotnet[Boosting Performance With Sealed Classes in .NET]
|
||||
* https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6/#peanut-butter[Performance Improvements in .NET 6]
|
@ -1,39 +1,12 @@
|
||||
== Why is this an issue?
|
||||
include::why.adoc[]
|
||||
|
||||
``++private++`` classes and records aren't visible outside of their assemblies anyway, so if they're not extended inside the assemblies, they should be made explicitly non-extensible with the addition of the ``++sealed++`` keyword.
|
||||
include::impact.adoc[]
|
||||
|
||||
include::how.adoc[]
|
||||
|
||||
=== Noncompliant code example
|
||||
|
||||
[source,csharp]
|
||||
----
|
||||
private class MyClass // Noncompliant
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
private record MyRecord // Noncompliant
|
||||
{
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
=== Compliant solution
|
||||
|
||||
[source,csharp]
|
||||
----
|
||||
private sealed class MyClass
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
private sealed record MyRecord
|
||||
{
|
||||
// ...
|
||||
}
|
||||
----
|
||||
include::code.adoc[]
|
||||
|
||||
include::resources.adoc[]
|
||||
|
||||
ifdef::env-github,rspecator-view[]
|
||||
|
||||
|
3
rules/S3260/csharp/why.adoc
Normal file
3
rules/S3260/csharp/why.adoc
Normal file
@ -0,0 +1,3 @@
|
||||
== Why is this an issue?
|
||||
|
||||
Classes and records with either `private` or `file` access modifiers aren't visible outside of their assemblies or files, so if they're not extended inside their scope, they should be made explicitly non-extensible with the addition of the `sealed` keyword.
|
Loading…
x
Reference in New Issue
Block a user