Created
April 20, 2021 15:34
-
-
Save usametov/48901681f5367e5dc123d400fe4f55e6 to your computer and use it in GitHub Desktop.
CSharp nullable types notes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// using the same syntax as for value types | |
string nonNullable = null; // compiler warning | |
string? nullable = null; | |
// here is breaking change in a new version of the language, | |
// the nullable reference types is the only feature of C# 8 that isn’t enabled by default | |
//look: before C# 8 | |
string nullableString; | |
//now it looks the same, but semantic changed | |
// since C# 8 | |
string nonNullableString; | |
// add this setting to the project file for that: | |
//<Nullable>enable</Nullable> | |
// In recent versions of Visual Studio 2019, | |
// this option is available on the Build page of the Project Properties window | |
// While assigning a null value to a non-nullable value type causes a compiler error, | |
// doing the same with a non-nullable reference type will only result in a warning (!) | |
// But we can still treat it as an error using the 'Treat warnings as errors' compiler option. | |
string nonNullable = null // warning at compile time | |
string? nullable = null; | |
string nonNullable = nullable; // warning at compile time | |
var length = nullable.Length; // warning at compile time | |
// static analysis is not perfect. | |
// Even if you get rid of all the warnings, there is still a possibility of a NullReferenceException being thrown at run time | |
var person = new Person("John", "Doe", "Unknown"); | |
if (person.HomeCountry != null) | |
{ | |
person.Relocate(); // sets HomeCountry to null | |
var countryLength = person.HomeCountry.Length; // no warning | |
} | |
// a new #nullable directive has been introduced into the language. | |
// use it to enable or disable the nullable reference types feature inside a single source code file. | |
// just put the following at the top fo the file: | |
#nullable disable // other options are 'enable' and 'restore' | |
// .net 5 annotated 94% of the netcoreapp assemblies for nullable reference types. | |
// In .NET 6.0/.NET 7.0, we plan to annotate the remaining 6% of that surface area | |
// and continue through other assemblies built from the dotnet/runtime repo. | |
//officially supported way to add annotations for nullable reference types to a .NET Standard 2.0 library | |
// manually add the following property to the project file to enable the use of C# 8: | |
<LangVersion>8.0</LangVersion> | |
// Json.net lib supports nullable reference types only from version 12 | |
// even in version 12, code analysis won’t detect all potential NullReferenceExceptions thrown at run time | |
Player player = JsonConvert.DeserializeObject<Player>("null"); //assigns null to player | |
var username = player.Username; // no warning | |
// The only way to get a compile-time warning would be to modify the first line of code as follows: | |
var player = JsonConvert.DeserializeObject<Player?>("null"); | |
var username = player.Username; // now we get warning | |
// notnull constraint can be useful in certain scenarios, | |
// but it doesn’t solve the initial problem of the missing warning. | |
// Even worse. It prevents the consuming code from using a nullable reference type | |
// as the generic type argument to get the compiler warning. | |
// But it does ensure that the type argument will always be nonnullable. | |
// we should add [return: MaybeNull] annotation attribute to get a compile time warning | |
[return: MaybeNull] | |
public static T DeserializeObject<T>(string json) where T: notnull | |
{ | |
return JsonConvert.DeserializeObject<T>(json); | |
} | |
// MaybeNull attribute specifies that the return type value will be a nullable reference type | |
// even if the generic type argument is a non-nullable reference type | |
// a few more annotation atttributes are available: | |
// MaybeNull and NotNull have the exact opposite meaning | |
// Conditional variations for both are also available: | |
// MaybeNullWhen, NotNullWhen, and NotNullIfNotNull. | |
//for input values we have AllowNull and DisallowNull annotation attributes | |
// https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis | |
// entity framework core docs | |
// https://docs.microsoft.com/en-us/ef/core/miscellaneous/nullable-reference-types | |
// To tell the compiler that the value is initialized without initializing it yourself, | |
// use the null-forgiving operator ! | |
// null-forgiving operator tells the compiler to ignore that warning | |
public DbSet<Player> Players { get; set; } = null!; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment