StrictCSharp.Analyzers 0.1.3

dotnet add package StrictCSharp.Analyzers --version 0.1.3
                    
NuGet\Install-Package StrictCSharp.Analyzers -Version 0.1.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="StrictCSharp.Analyzers" Version="0.1.3">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="StrictCSharp.Analyzers" Version="0.1.3" />
                    
Directory.Packages.props
<PackageReference Include="StrictCSharp.Analyzers">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add StrictCSharp.Analyzers --version 0.1.3
                    
#r "nuget: StrictCSharp.Analyzers, 0.1.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package StrictCSharp.Analyzers@0.1.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=StrictCSharp.Analyzers&version=0.1.3
                    
Install as a Cake Addin
#tool nuget:?package=StrictCSharp.Analyzers&version=0.1.3
                    
Install as a Cake Tool

StrictCSharp.Analyzers

A set of strict .NET Compiler Platform (Roslyn) Analyzers for C# projects.

Installation

Install the package via NuGet:

dotnet add package StrictCSharp.Analyzers

Or add it to your .csproj file:

<ItemGroup>
  <PackageReference Include="StrictCSharp.Analyzers" Version="0.0.2" />
</ItemGroup>

Available Analyzers

All analyzers are configured as errors by default to enforce strict coding standards. See Configuration for more details on how to disable or change the severity of individual analyzers.

Documentation Analyzers

SC021 - TypeDocumentationAnalyzer

Definition: Requires all public types to have XML documentation.

Motivation: Public APIs should explain both what they do and why they do it, to help consumers understand how to use them. This is especially important in the age of AI-generated code, for helping both humans and AIs with understanding.

While excessive documentation can be hard to maintain, requiring XML documentation on only public types provides good value with minimal maintenance effort.


Naming Analyzers

SC041 - WeaselWordNameAnalyzer

Definition: Prohibits type names ending with generic suffixes like 'Service', 'Manager', 'Helper', or 'Util'.

Motivation: These suffixes do not convey meaningful information about what the class actually does, and promote classes with multiple responsibilities. If you find yourself using a weasel word, you should think of a better abstraction.


Style Analyzers

SC101 - UsingBlockAtEndAnalyzer

Definition: Requires using statement expressions instead of using blocks when the using is the last statement in a method.

Motivation: Using statement expressions (using var x = ...) are more concise and reduce nesting compared to using blocks (using (var x = ...) { ... }). When the using is the last statement, the block adds unnecessary indentation without providing value.

SC121 - ManualParameterValidationAnalyzer

Definition: Requires using Ardalis.GuardClauses for parameter validation instead of manual if-throw patterns.

Motivation: Guard clauses provide a concise and consistent way to validate parameters. The Ardalis.GuardClauses library is the most well fleshed-out and widely used guard clause library in the .NET ecosystem.

SC122 - GuardClauseNameofAnalyzer

Definition: Prohibits using nameof for the second parameter in Guard.Against calls.

Motivation: The Ardalis.GuardClauses library uses CallerArgumentExpression on the second parameter to automatically capture the expression name. Using nameof is redundant and unnecessary.

SC141 - NoInlineCommentsAnalyzer

Definition: Prohibits inline comments (// or /* */).

Motivation: Code should be self-explanatory. If you need a comment to explain what code does, consider extracting it into a well-named method instead. This is especially important in the age of AI-generated code, because LLMs have a tendency to sprinkle comments absolutely everywhere.

For public APIs, use XML documentation comments instead.


Testing Analyzers

SC201 - NoXUnitAssertionsAnalyzer

Definition: Requires using FluentAssertions instead of xUnit's Assert methods.

Motivation: FluentAssertions provides more readable assertions with better error messages. Compare Assert.Equal(expected, actual) to actual.Should().Be(expected). FluentAssertions also provides detailed failure messages that show exactly what went wrong.

SC204 - NoTaskDelayAnalyzer

Definition: Prohibits await Task.Delay() in tests.

Motivation: Unit tests should be fast and deterministic. Task.Delay() makes tests slow and can introduce flakiness due to timing issues.

SC221 - ArrangeActAssertAnalyzer

Definition: Requires test methods to have // Arrange, // Act, and // Assert comments marking each section.

Motivation: The Arrange-Act-Assert pattern makes tests easier to read and understand. Explicit comments enforce this structure and help readers quickly identify what's being set up, what action is being tested, and what's being verified. Additionally, explicit sections denoted by comments make it easy to see when one of the sections is getting too large, and could benefit from refactoring.

SC222 - FluentAssertionScopeAnalyzer

Definition: Requires using AssertionScope when a test method has multiple FluentAssertions.

Motivation: Without AssertionScope, tests stop at the first failed assertion. With AssertionScope, all assertions are evaluated and you see all failures at once, making it faster to fix multiple issues.

SC223 - CategoryTraitAnalyzer

Definition: Requires test classes to have a [Trait("Category", ...)] attribute.

Motivation: Categorizing tests allows you to run specific subsets of tests (e.g., unit tests vs integration tests). This also helps developers understand which tests are unit tests and should not make external calls, and which tests are integration tests and can make external calls.

SC241 - TestClassMustEndWithTestsAnalyzer

Definition: Requires test classes to end with the suffix "Tests".

Motivation: Consistent and explicit naming conventions make it easy to identify test classes at a glance.

SC242 - TestMethodNamingAnalyzer

Definition: Requires test methods to follow the 3-segment naming pattern: MethodName_Scenario_ExpectedResult.

Motivation: This naming convention makes test intent crystal clear. For example, Authenticate_WithInvalidPassword_ThrowsAuthenticationException tells you exactly what's being tested, under what conditions, and what should happen.

SC243 - TestOfRequiredAnalyzer

Definition: Requires test classes to have a [TestOf(typeof(...))] attribute.

Motivation: This attribute explicitly links test classes to the code they test, making it easy to find tests for a given class and ensuring tests are organized around the code under test.

SC244 - TestClassNamespaceAnalyzer

Definition: Requires test class namespaces to match the namespace of the class under test.

Motivation: Mirroring namespaces between production code and tests makes it easy to navigate between them, and easy to find which classes are missing tests.

Configuration

All analyzers are enabled by default when you install the package. You can selectively enable or disable analyzers using an .editorconfig file in your project.

Disabling Individual Analyzers

To disable specific analyzers, add entries to your .editorconfig file:

root = true

[*.cs]
# Disable specific analyzers by their diagnostic ID
dotnet_diagnostic.SC021.severity = none  # Type documentation
dotnet_diagnostic.SC041.severity = none  # Weasel word names
dotnet_diagnostic.SC141.severity = none  # Inline comments

Disabling Analyzers by Category

You can disable entire categories of analyzers:

[*.cs]
# Disable all testing rules
dotnet_analyzer_diagnostic.category-Testing.severity = none

# Disable all documentation rules
dotnet_analyzer_diagnostic.category-Documentation.severity = none

# Disable all naming rules
dotnet_analyzer_diagnostic.category-Naming.severity = none

# Disable all style rules
dotnet_analyzer_diagnostic.category-Style.severity = none

Changing Severity Levels

You can also change the severity of analyzers instead of disabling them:

[*.cs]
# Change from error to warning
dotnet_diagnostic.SC021.severity = warning

# Change from warning to error
dotnet_diagnostic.SC201.severity = error

# Available severity levels: none, silent, suggestion, warning, error

Analyzer Categories

The analyzers use a structured diagnostic ID system with the prefix SC (StrictCSharp) followed by a three-digit number:

0xx - Core/Fundamental Rules (000-099)

Rules that enforce fundamental project configuration and essential code quality standards.

  • 000-019: Project Configuration

    • Project-level settings like warnings as errors, nullable context, required analyzer packages
  • 020-039: Documentation Requirements

    • XML documentation requirements, comment quality checks
  • 040-059: Naming Conventions

    • Type and member naming rules, forbidden naming patterns

1xx - Style/Code Quality Rules (100-199)

Rules that enforce consistent coding style and improve code readability.

  • 100-119: Using Statements & Resource Management

    • Using statement patterns, resource disposal
  • 120-139: Method/Member Style

    • Expression bodies, guard clauses, method structure
  • 140-159: Comment Style

    • Inline comment restrictions, comment formatting

2xx - Testing Rules (200-299)

Rules specific to test code organization, structure, and quality.

  • 200-219: Test Framework Requirements

    • Allowed testing frameworks, assertion libraries, forbidden test patterns
  • 220-239: Test Structure

    • Test attributes, test organization, assertion patterns
  • 240-259: Test Naming & Organization

    • Test class naming, namespace organization, method naming patterns

9xx - Meta/Configuration Rules (900-999)

Rules about analyzer configuration and rule management.

  • 900-919: Analyzer Configuration
  • 920-939: Suppression Rules
  • 940-959: Severity Configuration

Roadmap

Internal improvements

  • Set up nuget package publish
  • Document motivation for the project in this readme
  • Ensure each analyzer explains Motivation
  • Create enum for analyzer categories
  • Use published analyzers in this codebase
  • Convert to centralized package management

Analyzer improvements

  • Figure out consistent analyzer naming (e.g. SomethingRequiredAnalyzer or SomethingForbiddenAnalyzer) (Require/Enforce vs Forbid/Prohibit)
  • Directory.build.props for consistent project settings
  • TestCategory enum/constants
  • Remove region support from AAA analyzer
  • Update TestOf to also specify the method under test

New analyzers

  • Warnings as errors must be enabled
  • nullable context must be enabled
  • Require microsoft threading analyzers
  • No pramga warning disable
  • dumb comment analyzer (detect if the comment is mostly just the property name)
  • Single-line members must be expression bodies
  • Class name must match file name
  • Don't allow empty param/return tags in XML comments
  • Limit C# file length to like 300 lines?
Testing
  • Only allow Xunit tests
  • Forbid multiple assertions per test
  • Test classes must only test a single method
  • Test methods must follow the pattern ScenarioUnderTest_ExpectedBehavior (currently 3 segments)
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.3 270 11/16/2025
0.1.2 251 11/16/2025
0.1.1 237 11/16/2025
0.1.0 198 10/14/2025
0.0.2 133 10/12/2025
0.0.1 136 10/12/2025