C# 8.0 - Nullable Reference Types
نویسنده: وحید نصیری
تاریخ: ۱۳۹۸/۰۳/۰۷ ۱۳:۰
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<LangVersion>8.0</LangVersion>
<NullableContextOptions>enable</NullableContextOptions>
</PropertyGroup>
</Project> CS8632: The annotation for nullable reference types should only be used in code within a ‘#nullable’ context. CS8627: A nullable type parameter must be known to be a value-type or non-nullable reference type. Consider adding a ‘class’, ‘struct’ or type constraint.
<PropertyGroup> <LangVersion>preview</LangVersion> <Nullable>enable</Nullable> </PropertyGroup>
public class Person
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public Person(string first, string last) =>
(FirstName, LastName) = (first, last);
public Person(string first, string middle, string last) =>
(FirstName, MiddleName, LastName) = (first, middle, last);
public override string ToString() => $"{FirstName} {MiddleName} {LastName}";
}
public string? MiddleName { get; set; } public static class NullableReferenceTypes
{
//#nullable enable // Toggle to enable
public static string Exemplify()
{
var vahid = new Person("Vahid", "N");
var length = GetLengthOfMiddleName(vahid);
return $"{vahid.FirstName}'s middle name has {length} characters in it.";
static int GetLengthOfMiddleName(Person person)
{
string middleName = person.MiddleName;
return middleName.Length;
}
}
}
var middleName = person.MiddleName;
static int GetLengthOfMiddleName(Person person)
{
var middleName = person.MiddleName;
return middleName?.Length ?? 0;
} public static class NullableReferenceTypes
{
#nullable disable // Toggle to enable <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<LangVersion>8.0</LangVersion>
<NullableContextOptions>enable</NullableContextOptions>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
</Project> <WarningsAsErrors>CS8600;CS8602;CS8603</WarningsAsErrors>
string name = null; // ERROR string? name = null; // OK!
public class Person
{
public Address? Address { get; set; };
public string Country => Address?.Country; // ERROR!
} public class Person
{
public Address? Address { get; set; };
public string? Country => Address?.Country; // OK!
} var node = this; // Initialize non-nullable variable
while (node != null)
{
node = null; // ERROR!
} Node? node = this; // Initialize nullable variable
while (node != null) {
node = null; // OK!
} public class Person
{
public string Name { get; set; } // ERROR!
} public class Person
{
public string? Name { get; set; }
} public class Person
{
public string Name { get; set; }
public Person(string name) {
Name = name ?? throw new ArgumentNullException(nameof(name));
}
}
public class Person
{
public string Name { get; set; } = string.Empty;
// -or-
public string Name { get; set; } = "";
} String.Empty Array.Empty<T>() Enumerable.Empty<T>()
public class Person
{
public Address Address { get; set; } = new Address();
} <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project> interface IDoStuff<TIn, TOut> where TIn : notnull where TOut : notnull
{
TOut DoStuff(TIn input);
} using System;
using System.Diagnostics.CodeAnalysis;
namespace ConsoleApp
{
public class MyClass
{
private string _innerValue = string.Empty;
[AllowNull]
public string MyValue
{
get
{
return _innerValue;
}
set
{
_innerValue = value ?? string.Empty;
}
}
} public class MyArray
{
// Result is the default of T if no match is found
[return: MaybeNull]
public static T Find<T>(T[] array, Func<T, bool> match)
{
//...
}
// Never gives back a null when called
public static void Resize<T>([NotNull] ref T[]? array, int newSize)
{
//...
}
} public class MyString
{
// True when 'value' is null
public static bool IsNullOrEmpty([NotNullWhen(false)] string? value)
{
//...
}
} public class MyVersion
{
// If it parses successfully, the Version will not be null.
public static bool TryParse(string? input, [NotNullWhen(true)] out Version? version)
{
//...
}
} public class MyQueue<T>
{
// 'result' could be null if we couldn't Dequeue it.
public bool TryDequeue([MaybeNullWhen(false)] out T result)
{
//...
}
} class MyPath
{
[return: NotNullIfNotNull("path")]
public static string? GetFileName(string? path)
{
//...
}
} internal static class ThrowHelper
{
[DoesNotReturn]
public static void ThrowArgumentNullException(ExceptionArgument arg)
{
//...
}
} public static class MyAssertionLibrary
{
public static void MyAssert([DoesNotReturnIf(false)] bool condition)
{
//...
}
} string? s1 = "Hello"; string s2 = s1!;
public class Person_BeforeCS8
{
[Required]
public string FirstName { get; set; } // NOT NULL
public string MiddleName { get; set; } // NULL
} public class Person_AfterCS8
{
public string FirstName { get; set; } = null!; // NOT NULL
public string? MiddleName { get; set; } // NULL
} var parentPosts = db.Posts.Where(p => p.ParentPost.Id == postId).ToList();
var parentPosts = db.Posts.Where(p => p.ParentPost!.Id == postId).ToList();
public class RegistrationForm_BeforeCS8
{
[Required]
public string FirstName { get; set; } // required field
public string MiddleName { get; set; } // optional field
} public IActionResult MyAction([Required]RegistrationForm form)
{
if (form == null || !ModelState.IsValid)
{
return View();
}
// .. blabla
} public class RegistrationForm_AfterCS8
{
public string FirstName { get; set; } = null!;// required field
public string? MiddleName { get; set; } // optional field
} public IActionResult MyAction(RegistrationForm form)
{
if (!ModelState.IsValid)
{
return View();
}
// .. blabla
} public static bool IsNullOrWhiteSpace(this string str)
=> string.IsNullOrWhiteSpace(str);public static bool IsNullOrWhiteSpace([NotNullWhen(returnValue: false)] this string? str)
=> string.IsNullOrWhiteSpace(str);