62

Using Visual Studio 2019 v16.3.2 with a .NET Core 3.0 project set to C# 8 and nullable reference types enabled.

<PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <LangVersion>8.0</LangVersion>
    <Nullable>enable</Nullable>
</PropertyGroup>

If I set it to treat all warnings as errors:

warnings as errors radio button selected

<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors />

It reports other warnings as errors. For example, CS0168 The variable 'x' is declared but never used is reported as an error. But all the nullable reference warnings are still reported as warnings. For example, CS8600 Converting null literal or possible null value to non-nullable type. is still reported as a warning.

How do I treat all nullable reference warnings as errors?

Note: even setting CS8600 specifically to be treated as an error doesn't cause it to be reported as an error. If that worked, it still wouldn't help with treating them all as errors because there are so many.

Edit: setting specific warnings to be treated as errors puts <WarningsAsErrors>CS8600;CS8602;CS8603</WarningsAsErrors> in the csproj and doesn't work.

Community
  • 1
  • 1
Jeff Walker Code Ranger
  • 4,634
  • 1
  • 43
  • 62
  • Try to add **CS8600;CS8602;CS8603** to csproj – Phat Huynh Oct 02 '19 at 04:12
  • 1
    I think your VS has problem. Same config work for me. Please try to reinstall your VS – Phat Huynh Oct 02 '19 at 04:31
  • are you building the project to get these warnings/errors, or is the problem happening in the editor window? there seem to be lots of synchronization issues with the compiler that's running in the code window, but it shouldn't be able to get past an actual build process. – Dave Cousineau Oct 02 '19 at 22:09
  • @officer's answer nails what you're looking for. It ought to be accepted as the answer here. – joelmdev Apr 16 '21 at 18:15

4 Answers4

98

It is now possible to treat all nullable-related warnings as errors without explicitly specifying them all. To achieve this, you have to set <WarningsAsErrors>Nullable</WarningsAsErrors> in your *.csproj file [source].

Full example:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <Nullable>enable</Nullable>
    <WarningsAsErrors>Nullable</WarningsAsErrors>
  </PropertyGroup>
</Project>

Josh Close
  • 22,935
  • 13
  • 92
  • 140
officer
  • 2,080
  • 1
  • 20
  • 29
  • be careful. You will have to treat all not null properties with fake init `= null!;` Is there any way to add all and then exclude certain ones? – SerjG Apr 27 '21 at 05:51
  • 2
    The question is explicitly about treating _all_ nullable warnings as errors. – officer Apr 27 '21 at 08:10
  • 1
    @SerjG Other than that, my approach to introduce the nullable feature in existing code bases is to use the `#nullable enable` pragma for new/changed files. The other way around could be to globally enable it but opt-out for your special files with `#nullable disable`. – officer Apr 27 '21 at 15:13
  • Not sure how can it help with all that annoying places with ` = null!` – SerjG Apr 29 '21 at 20:26
  • @SerjG: I don't get it: Why would you have such properties? Either it is nullable or it is not and then it must be initialized in some way, either directly in its declaration or in the constructor or by a helper method called in the constructor (use attribute `MemberNotNull`) or it gets initialized through a lazy getter and then the property is non-nullable with attribute `AllowNull` for the setter (but declared on the property) if it is allowed to clear the cached value and have it recreated by the next getter call. – Christoph Oct 08 '21 at 10:58
  • @SerjG: Or you have properties where it is invalid to assign `null` which do not need to be initialized, then that would be a nullable property with attribute `DisallowNull` for the setter (but declared on the property). – Christoph Oct 08 '21 at 11:00
  • @Christoph we have a lot of JSON models which will ne initialized one deserialized. And yes, we are too lazy to create .ctors. – SerjG Oct 11 '21 at 16:45
  • @SerjG: But would that not be a classic usage of nullable reference types? Each property may be null, may have been serialized as null, may not have been serialized because the model changed after the serialization or the JSON data was changed manually etc.? I personally would make all value- and reference types of DTO properties nullable (the nullalbe value types only of new or private interfaces as it breaks the existing contract), and the method receiving the DTO validates whether all mandatory properties are initialized and contain sensible values... – Christoph Oct 13 '21 at 15:40
  • @Christoph no it's not. We mark with ? properties which can be deserialized as null. Validation is not enough to make analyzer think that value is presented. So we have to use ! or transform to some other object which has not null properties. Both ways are annoying – SerjG Oct 15 '21 at 18:05
  • @SerjG: But that concept does not work imho: What if a non-nullable reference property is not included in the serialized JSON for whatever reason? It becomes `null` when deserialized and is passed on as `null` but you guarantee it is non-`null` in your contract. – Christoph Oct 21 '21 at 11:15
  • @Christoph yes. It's a trade-off between a lot of null checks and correct nullability usage. Also we have validation for required properties and should not work with invalid objects – SerjG Oct 21 '21 at 14:35
12

I would suggest to use this solution. It mentions all 3 errors and IMHO better solution

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <LangVersion>8.0</LangVersion>
    <WarningsAsErrors>CS8600;CS8602;CS8603</WarningsAsErrors>
  </PropertyGroup>
</Project>

screen


Update:

We have this list now: <WarningsAsErrors>CS8600;CS8601;CS8602;CS8603;CS8613;CS8625;CS8629;CS8614;CS8619;CS8633</WarningsAsErrors>

Update 2021-04:

We have this list now: <WarningsAsErrors>CS8600;CS8601;CS8602;CS8603;CS8604;CS8613;CS8614;CS8619;CS8620;CS8622;CS8625;CS8629;CS8633,CS8767</WarningsAsErrors>

Update 2023-05:

We have this list now: <WarningsAsErrors>CS8600;CS8601;CS8602;CS8604;CS8613;CS8614;CS8619;CS8620;CS8622;CS8625;CS8629;CS8633;CS8524;CS8509;CS8524;CS8767</WarningsAsErrors>

SerjG
  • 3,325
  • 3
  • 30
  • 30
  • 3
    Regarding your update: maybe `CS8618 C# Non-nullable property is uninitialized. Consider declaring the property as nullable.` might also be relevant to include. – officer May 31 '20 at 13:10
  • 1
    @officer this is what we are trying to avoid for all DTOs, models and other classes which will never be created with `new()` – SerjG Apr 27 '21 at 05:52
7

The problem was that the .editorconfig file was overriding the Visual Studio setting to treat all warnings as errors with many lines like:

dotnet_diagnostic.CS8602.severity = warning

This forces CS8602 to be a warning.

How this happened: In a previous attempt at turning all nullable reference warnings into errors, I set many of them as errors in the editor config. In that, I discovered both that there were a ton of different warning numbers and that my codebase wasn't ready for them to be errors throughout the entire solution. So I set them to "warning" in the editor config because I didn't want to lose the list of warnings I had found. Then later, having forgotten all about that, I decided to turn on treat warnings as errors on a project by project basis.

Jeff Walker Code Ranger
  • 4,634
  • 1
  • 43
  • 62
1

Since Google is pointing to this question when one asks for <WarningsAsErrors>Nullable</WarningsAsErrors>, I would like to point out that if you googling why it isn't working (produce build errors) and you inject this by Directory.Build.props, it won't work by design.

The property gets injected from the Directory.Build.props, but gets overridden by the CSProj default (no error on build).

The approach with Directory.Build.targets removes a possibility to override this from CSProj completely.

More granular approach would be probably by using the root .editorconfig and list the behavior explicitly with possible local override.

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
KUTlime
  • 5,889
  • 1
  • 18
  • 29