My desk is a mess. There's papers, stickers, spare parts, glasses cleaning cloths, at least one coffee cup, tiny plush toys, and lots of knick knacks and other crap. It is my mess and I know where everything is so it's not a problem... until my wife needs to get something off the desk.
Luckily it's a rare thing that she needs to get something off my desk, and I can usually guide her to whatever she's after. So what all of this have to do with coding and Roslyn Analyzers? Unlike my desk, which is almost only accessed by me, the code I write is almost always read by others. It starts with a code review, but will continue for years as others maintain and add features to the code. So, unlike my mess on the desk, messy code is the entire teams problem.
Identify messy code
Messy code is any code that doesn't follow your coding style. However, without tooling to help, a coding style is just another document that very few will read. Luckily in .NET (or dotnet if you are in the #dropthedot crowd...) there are tools built right into the compiler, the .NET Compiler Platform (Roslyn) Analyzers, or Roslyn Analyzers for short.
If you haven't specified your own coding style, a good starting point is to use the official coding conventions provided by Microsoft
You can also look at the Framework Design Guidelines on how to design libraries to look, feel and behave in a dotnet:y way.
What can the Roslyn Analyzers help us with?
Code Style rules
Code Style rules help with maintaining a coding style throughout code and are grouped into 5 categories and are named
Defines how the code is written using the language features, such as using parenthesis for clarification or prepending local calls with
- Unnecessary code
Detects code that can be simplified or code that is not in use. Since this is a compile time analysis, code called using reflection and magic strings are likely not detected.
This contains some rules around wrong or old usage of
Contains one rule IDE0055, which is all the things formatting. It validates configuration around new lines, indentation, spacing and how using directives are sorted.
Contains one rule IDE1006 with a very customizable configuration for how fields, properties, classes etc are named. Should local fields be prepended with
_, should methods use cameCase or PascalCase and lots more.
Code Quality Rules
Code Quality rules are there to help writing better and safer code by warning when the code isn't using the .NET APIs as expected, or when the code references unsafe methods and more. These rules are grouped into 11 categories and are mostly named
Helps with following the .NET Framework Design Guidelines with rules to ensure the code validates arguments in public methods, enums have zero values, classes are declared in a namespace and lots more.
In .NET 7 there's only one rule CA1200 which validates that
crefin XML-documentation doesn't include prefixes.
Helps with code that is affected by the current culture or that is used to localize the application.
- Portability and interoperability
Validates rules when interacting with COM clients.
Rules to help write more maintainable code, such as not using large dependency trees and using
nameof()instead of magic strings.
Warns if names violating the .NET naming guidelines for example enums with Flag attribute should be pluralized and identifiers should not differ only by case.
Contains a bunch of rules to help writing more performant code, for instance using
Countproperties instead of Linq's
These rules have the name IL3000 to IL3003 and help with issues related to publishing as single file, like avoid the property
Assembly.Locationsince it returns
string.Emptywhen publishing as single file.
Helps with writing code that use threads and memory correctly, for example disposing objects that implement
Provide assistance to discover SQL Injection, using unsafe encryption algorithms, using antiforgery tokens in ASP.NET Core MVC Controllers, and lots more.
These rules helps with writing code that could cause unexpected behavior or that are likely to cause issues. For example warn when calling virtual methods inside a constructor, or passing a URI as a
stringwhen there is a overload that accepts [codespan lang="csharp"]Uri[/codespan.].
How to enable the Roslyn Analyzers
So how do we enable the Roslyn Analyzers? Short answer, if you are targeting net5.0 or above they are already enabled, but only a small set of rules. If you are targeting a version earlier than net5.0, for instance net472, the analyzers can be enabled in the project file, as long as you are using a SDK-style project file.
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net472</TargetFramework> <EnableNETAnalyzers>true</EnableNETAnalyzers> </PropertyGroup> </Project>
If you're not using an SDK-style project file, you can use a NuGet package Microsoft.CodeAnalysis.NetAnalyzers.
Configure the Roslyn Analyzers
In .NET 7 20 rules out of several hundreds are enabled by default. The reason why there are so few rules enabled by default is that enabling more rules would possibly break a lot of builds out there that treat warnings as errors.
To enable more rules there's two main paths, enabling more rules in the project file or adding rule severity in the
Configuration in the project file
To configure which rules are analysed, add the element
AnalysisLevel to the project file.
<PropertyGroup> <AnalysisLevel>latest-all</AnalysisLevel> </PropertyGroup>
The value for
<AnalysisLevel> is made up of two parts, the version and the mode:
<version>-<mode>. For instance the above will analyze all rules based on the latest version of the .NET SDK.
The version specifies which rules to analyze based on the .NET version specified. Uses can be
latest or the current version,
preview any preview that might be installed, or any specific version such as
Mode sets the amount of rules to analyze. The amount of rules include in order of increased amount of rules from
none (disable all),
all. It's a rather rough way of determining which rules that are used, but it will get you started.
Back in the .NET 5 SDK days,
<AnalysisLevel> only contained the version and the mode was set using
<AnalysisMode>. In .NET 6 support for the compound value was added, but the non-compount way is still supported.