This project enhances the exhaustiveness check of the C# compiler for switch statements and switch expressions on the OneOf<...>.Value
property from the OneOf library.
This gives you all the syntactic power of native switch
while keeping compile-time safety. Compile-time safety is achieved by escalating the exhaustiveness diagnostics' severity to error in your .editorconfig
.
See this issue.
(If you are using structurally closed type hierarchies instead, see my other repo ClosedTypeHierarchyDiagnosticSuppressor.)
using OneOf;
#nullable enable
// without this suppressor: warning CS8509
// with this suppressor: no warnings
public static int Get(OneOf<int, string> intOrString) => intOrString.Value switch
{
int => 1,
string => 2
};
#nullable disable
// without this suppressor: warning CS8509
// with this suppressor: no warnings
public static int Get(OneOf<int, string> intOrString) => intOrString.Value switch
{
int => 1,
string => 2
// without NRTs, null must be matched to be exhaustive
null => 0
};
Get on nuget.org or just include with
<PackageReference Include="SvSoft.OneOf.Analyzers.SwitchDiagnosticSuppression" Version="0.0.1" PrivateAssets="All" />
There are no attributes and no configuration. It will just do The Right Thing™.
See the test samples for switch statement and switch expression to see what is supported. I may add more documentation and examples in this README soon.
In your project, enable IDE0010 (for switch statements) and IDE0072 (for switch expressions, not strictly necessary because we have CS8509 anyway) like this:
<PropertyGroup>
<!-- enables (among others) IDE0010 and IDE0072 -->
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup>
In your .editorconfig
configure the severity of the exhaustiveness diagnostics:
[*.cs]
dotnet_diagnostic.IDE0010.severity = error
dotnet_diagnostic.IDE0072.severity = error
dotnet_diagnostic.CS8509.severity = error
If you set diagnostic severity to error for diagnostics that may be suppressed by a diagnostic suppressor like this one, you may have to take additional action for a good development experience.
By default, Visual Studio does not run diagnostic suppressors when the build is implicitly triggered like by running a test. If you have errors that are suppressed by diagnostic suppressors, those builds will fail, e. g. preventing the test from running (unless you do an explicit build first). You can configure Visual Studio to always run analyzers (towards whom diagnostic suppressors are counted):
See also here.
Rider does not support Diagnostic Suppressors as of 2022-07-31. Your development experience may suffer.
OmniSharp and thus Visual Studio Code does not support Diagnostic Suppressors as of 2022-07-31. Your development experience may suffer.
Thanks to rutgersc for bringing this up.
Visual Studio for Mac does not support Diagnostic Suppressors as of 2023-01-06.
Pattern matching, including nested pattern matching is taken into account.
OneOf
encourages you to use its Match
method and supply N lambda expressions to do the switching. This has the advantage that breaking changes in the type arguments of the OneOf<...>
instance on which you are switching lead to compiler errors, because the number or type of the lambdas no longer fits.
However, this approach can be cumbersome in some cases.
It prevents you from using pattern matching.
It is also inferior to C#'s native switch
expression when it comes to type inference.
Because OneOf<...>.Value
is of type object
, using a native switch
expression on Value
will lead to compiler warnings about exhaustiveness.
This may tempt you to either include a default/discard case, or suppress the exhaustiveness warning. In both scenarios you lose compile-time checking and will not get a warning when the type arguments of the underlying OneOf<...>
change.
Hence this project, that will suppress the exhaustiveness warnings based on the guarantees that the OneOf library provides.
As long as you match all type arguments (and maybe null
), you will no longer get exhaustiveness warnings.
Now that there are no more false positives, you can escalate the exhaustiveness diagnostics to errors in your .editorconfig
.
You now have the best of both worlds: the syntactic power of native switch
and the compile-time safety of OneOf
's Match
method.
It is implemented as a DiagnosticSuppressor
.
It suppresses the compiler's own exhaustiveness warnings only when it is sure that the switch is exhaustive.
It suppresses IDE0010, IDE0072 and CS8509.