C# compiler strict mode

 
 
  • Gérald Barré

The C# compiler has some hidden features. The author of a GitHub issue pointed out that the C# compiler silently allows comparing an IntPtr with null, even though the result is always false at runtime, and suggested the compiler should report this as an error. Sam Harwell responded by describing a compiler option, /features:strict, that catches this and several other potential errors in your code.

To enable it, you must add <Features>strict</Features> to your csproj file:

XML
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <Features>strict</Features>
    <AnalysisLevel>latest</AnalysisLevel>
  </PropertyGroup>
</Project>

If your solution has many projects and you want to enable this compiler option for all projects, you can create a file named Directory.Build.props at the root of your solution with the content (MSBuild documentation):

csproj (MSBuild project file)
<Project>
  <PropertyGroup>
    <Features>strict</Features>
  </PropertyGroup>
</Project>

Here are some errors detected by the strict feature:

C#
IntPtr ptr = IntPtr.Zero;
if (ptr == null) // Warning CS8073 The result of the expression is always 'false' since a value of type 'IntPtr' is never equal to 'null' of type 'IntPtr?'
C#
lock (null) // Error CS0185 '<null>' is not a reference type as required by the lock statement
{
}
C#
var o = new object();
if (o is Math) // Error CS7023 The second operand of an 'is' or 'as' operator may not be static type 'Math'
{
}
C#
// In assembly A
public struct S
{
    private object _f;
}

// In assembly B
public class C
{
   void M()
   {
      S s; // Error CS0165: Use of unassigned local variable 's' (https://github.com/dotnet/roslyn/blob/master/docs/compilers/CSharp/Definite%20Assignment.md#definite-assignment-of-structs-across-assemblies)
   }
}
C#
enum Color { Black, Yellow, Red, White }
static void Bar()
{
    _ = 1 - Color.Red; // Error CS0019: Operator '-' cannot be applied to operands of type 'int' and 'Color'
}
C#
var func = new Func<string, string>(x => x);
_ = new Func<string, string>(ref func); // Error CS0149: Method name expected
C#
static void Demo(out ImmutableArray<string> result) // Error CS0177: The out parameter 'result' must be assigned to before control leaves the current method
{
}

// For more information: https://github.com/dotnet/roslyn/issues/13203

I hope this flag becomes the default behavior in a future release of C#, ideally enabled automatically based on the language version. For now, you must enable it manually.

Note that this flag is undocumented and not widely known. Following the GitHub discussion, CoreCLR opened a pull request to adopt this option in their codebase (Fix invalid IntPtr == null comparisons, set strict mode for Roslyn). It has also helped detect issues in PowerShell Core.

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?