Thursday, 28 January 2016

Backwards compatible ignoring Roslyn Analyzer warnings

The “Roslyn” Analyzers are a great new feature that shipped in Visual Studio 2015. One nice thing about them, is you can still add them to a project even if the target platform for a project is not .NET 4.6. This makes sense, as the analyzers just run as part of the compiler – they don’t affect the generated code in any way.

This also means you can safely add analyzers to a project and get all the warnings/errors when using Visual Studio 2015, but you can still open the same project in an older version of Visual Studio and the analyzers are just ignored.

Sometimes you want to suppress a specific warning. It turns out there’s two ways to do this:

SuppressMessageAttribute

The first is the same that you would have done to suppress an old FxCop/Code Analysis violation – using the System.Diagnostics.CodeAnalysis.SuppressMessageAttribute attribute.

[SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]

It turns out, the only bit that Roslyn really cares about is the second parameter. As long as it starts with a valid CheckId, then that violation will be suppressed. My observation is that the first parameter (category) doesn’t seem to matter too much.

[SuppressMessageAttribute("StyleCop", "SA1514")]

Pragmas

The new compiler is much more flexible in disabling warnings and errors. You can now use a compiler pragma to disable a particular warning or error code – and the code isn’t just for the C# language, it can be for an analyzer too. eg.

#pragma warning disable SA1514

One advantage to using pragmas is that you can re-enable them if you want to limit the scope of the pragma to just a particular block of code in a single file.

Backwards-compatible pragmas

The only problem with the pragma approach above is if you try and compile the source code with the older non-Roslyn C# compilers. They haven’t ever heard of this ‘SA1514’ that you’re referring to and will generate a compiler error. The workaround is to wrap the pragmas with a conditional block, like this:

#if VS2015 

#pragma warning disable SA1514
#endif

The final part is to define ‘VS2015’. Do this by editing the .csproj file and adding the following block (insert it after the last configuration/platform-specific PropertyGroup)

<PropertyGroup>   
  <DefineConstants Condition="$(VisualStudioVersion) &gt;= 14 ">$(DefineConstants);VS2015</DefineConstants>
</PropertyGroup>

This has the effect of defining a conditional constant only when we’re compiling with Visual Studio 14 (aka 2015) or above. For earlier versions, the constant is undefined and so the pragma is not visible to the compiler.

No comments: