Sündmused
17. märts, 21 - 21. märts, 10
Liituge sarjaga, et luua muude arendajate ja ekspertidega skaleeritavad tehisintellektilahendused, mis põhinevad reaalajas kasutusjuhtumitel.
Registreeruge koheSeda brauserit enam ei toetata.
Uusimate funktsioonide, turbevärskenduste ja tehnilise toe kasutamiseks võtke kasutusele Microsoft Edge.
This article covers the following compiler warnings:
[NotNull]
or [DisallowNull]
System.Runtime.CompilerServices.NullableAttribute
is not allowed.#nullable
annotations context./nullable
; must be disable
, enable
, warnings
or annotations
enable
, disable
, or restore
[DoesNotReturn]
should not return.[DoesNotReturn]
annotation to match implemented or overridden member.The purpose of nullable warnings is to minimize the chance that your application throws a System.NullReferenceException when run. To achieve this goal, the compiler uses static analysis and issues warnings when your code has constructs that might lead to null reference exceptions. You provide the compiler with information for its static analysis by applying type annotations and attributes. These annotations and attributes describe the nullability of arguments, parameters, and members of your types. In this article, you learn different techniques to address the nullable warnings the compiler generates from its static analysis. The techniques described here are for general C# code. Learn to work with nullable reference types and Entity Framework core in Working with nullable reference types.
Märkus
The static analysis can't always deduce in what order, in a specific scenario, methods are accessed, and whether the method completes successfully without throwing an exception. Those known pitfalls are well described in Known pitfalls section.
You address almost all warnings using one of five techniques:
?
or !
nullable annotations.If you're new to using nullable reference types, the overview of nullable reference types provides a background on what nullable reference types solve and how they work to provide warnings to possible mistakes in your code. You can also check the guidance on migrating to nullable reference types to learn more about enabling nullable reference types in an existing project.
The following warnings indicate that you haven't set the nullable context correctly:
#nullable
annotations context./nullable
; must be disable
, enable
, warnings
or annotations
enable
, disable
, or restore
Nullable reference types, including the operators ?
and !
are allowed only when the nullable context is set to enable
or annotations
. You can set the nullable annotation using the Nullable
compiler option in your project file, or using the #nullable
pragma in your source code.
These errors and warnings indicate that usage of the !
or ?
annotation is incorrect.
System.Runtime.CompilerServices.NullableAttribute
is not allowed.The ?
annotation in a declaration indicates that the variable might be null. It doesn't indicate a different runtime type. Both the following declarations are the same runtime type:
string s1 = "a string";
string? s2 = "another string";
The ?
is a hint to the compiler on the expectation for null values.
The !
annotation on an expression indicates that you know the expression is safe and should be assumed to be not null.
?
is an annotation, not a type, you can't use it with typeof
, or new
expressions.!
operator can't be applied to a variable expression or a method group.!
operator can't be applied to the left of a member access operator, such as obj.Field!.Method()
.This set of warnings alerts you that you're dereferencing a variable whose null-state is maybe-null. These warnings are:
The following code demonstrates one example of each of the preceding warnings:
class Container
{
public List<string>? States { get; set; }
}
internal void PossibleDereferenceNullExamples(string? message)
{
Console.WriteLine(message.Length); // CS8602
var c = new Container { States = { "Red", "Yellow", "Green" } }; // CS8670
}
In the preceding example, the warning is because the Container
, c
, might have a null value for the States
property. Assigning new states to a collection that might be null causes the warning.
To remove these warnings, you need to add code to change that variable's null-state to not-null before dereferencing it. The collection initializer warning can be harder to spot. The compiler detects that the collection maybe-null when the initializer adds elements to it.
In many instances, you can fix these warnings by checking that a variable isn't null before dereferencing it. Consider the following example that adds a null check before dereferencing the message
parameter:
void WriteMessageLength(string? message)
{
if (message is not null)
{
Console.WriteLine(message.Length);
}
}
The following example initializes the backing storage for the States
and removes the set
accessor. Consumers of the class can modify the contents of the collection, and the storage for the collection is never null
:
class Container
{
public List<string> States { get; } = new();
}
Other instances when you get these warnings might be false positive. You might have a private utility method that tests for null. The compiler doesn't know that the method provides a null check. Consider the following example that uses a private utility method, IsNotNull
:
public void WriteMessage(string? message)
{
if (IsNotNull(message))
Console.WriteLine(message.Length);
}
The compiler warns that you might be dereferencing null when you write the property message.Length
because its static analysis determines that message
might be null
. You know that IsNotNull
provides a null check, and when it returns true
, the null-state of message
should be not-null. You must tell the compiler those facts. One way is to use the null forgiving operator, !
. You can change the WriteLine
statement to match the following code:
Console.WriteLine(message!.Length);
The null forgiving operator makes the expression not-null even if it was maybe-null without the !
applied. In this example, a better solution is to add an attribute to the signature of IsNotNull
:
private static bool IsNotNull([NotNullWhen(true)] object? obj) => obj != null;
The System.Diagnostics.CodeAnalysis.NotNullWhenAttribute informs the compiler that the argument used for the obj
parameter is not-null when the method returns true
. When the method returns false
, the argument has the same null-state it had before the method was called.
Näpunäide
There's a rich set of attributes you can use to describe how your methods and properties affect null-state. You can learn about them in the language reference article on Nullable static analysis attributes.
Fixing a warning for dereferencing a maybe-null variable involves one of three techniques:
!
to the expression which forces the state to not-null.This set of warnings alerts you that you're assigning a variable whose type is nonnullable to an expression whose null-state is maybe-null. These warnings are:
The compiler emits these warnings when you attempt to assign an expression that is maybe-null to a variable that is nonnullable. For example:
string? TryGetMessage(int id) => "";
string msg = TryGetMessage(42); // Possible null assignment.
The different warnings indicate provide details about the code, such as assignment, unboxing assignment, return statements, arguments to methods, and throw expressions.
You can take one of three actions to address these warnings. One is to add the ?
annotation to make the variable a nullable reference type. That change can cause other warnings. Changing a variable from a non-nullable reference to a nullable reference changes its default null-state from not-null to maybe-null. The compiler's static analysis finds instances where you dereference a variable that is maybe-null.
The other actions instruct the compiler that the right-hand-side of the assignment is not-null. The expression on the right-hand-side could be null-checked before assignment, as shown in the following example:
string notNullMsg = TryGetMessage(42) ?? "Unknown message id: 42";
The previous examples demonstrate assignment of the return value of a method. You annotate the method (or property) to indicate when a method returns a not-null value. The System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute often specifies that a return value is not-null when an input argument is not-null. Another alternative is to add the null forgiving operator, !
to the right-hand side:
string msg = TryGetMessage(42)!;
Fixing a warning for assigning a maybe-null expression to a not-null variable involves one of four techniques:
This set of warnings alerts you that you're assigning a variable whose type is non-nullable to an expression whose null-state is maybe-null. These warnings are:
Consider the following class as an example:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Neither FirstName
nor LastName
are guaranteed initialized. If this code is new, consider changing the public interface. The preceding example could be updated as follows:
public class Person
{
public Person(string first, string last)
{
FirstName = first;
LastName = last;
}
public string FirstName { get; set; }
public string LastName { get; set; }
}
If you require creating a Person
object before setting the name, you can initialize the properties using a default non-null value:
public class Person
{
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
}
Another alternative is to change those members to nullable reference types. The Person
class could be defined as follows if null
should be allowed for the name:
public class Person
{
public string? FirstName { get; set; }
public string? LastName { get; set; }
}
Existing code sometimes require other changes to inform the compiler about the null semantics for those members. It might have multiple constructors, and your class has a private helper method that initializes one or more members. You can move the initialization code into a single constructor and ensure all constructors call the one with the common initialization code. Or, you can use the System.Diagnostics.CodeAnalysis.MemberNotNullAttribute and System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute attributes. These attributes inform the compiler that a member is not-null after the method returns. The following code shows an example of each. The Person
class uses a common constructor called by all other constructors. The Student
class has a helper method annotated with the System.Diagnostics.CodeAnalysis.MemberNotNullAttribute attribute:
using System.Diagnostics.CodeAnalysis;
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
public Person() : this("John", "Doe") { }
}
public class Student : Person
{
public string Major { get; set; }
public Student(string firstName, string lastName, string major)
: base(firstName, lastName)
{
SetMajor(major);
}
public Student(string firstName, string lastName) :
base(firstName, lastName)
{
SetMajor();
}
public Student()
{
SetMajor();
}
[MemberNotNull(nameof(Major))]
private void SetMajor(string? major = default)
{
Major = major ?? "Undeclared";
}
}
Finally, you can use the null forgiving operator to indicate that a member is initialized in other code. For another example, consider the following classes representing an Entity Framework Core model:
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
public class TodoContext : DbContext
{
public TodoContext(DbContextOptions<TodoContext> options)
: base(options)
{
}
public DbSet<TodoItem> TodoItems { get; set; } = null!;
}
The DbSet
property is initialized to null!
. That tells the compiler that the property is set to a not-null value. In fact, the base DbContext
performs the initialization of the set. The compiler's static analysis doesn't pick that up. For more information on working with nullable reference types and Entity Framework Core, see the article on Working with Nullable Reference Types in EF Core.
Fixing a warning for not initializing a nonnullable member involves one of four techniques:
null!
to indicate that the member is initialized in other code.Many warnings indicate nullability mismatches between signatures for methods, delegates, or type parameters.
The following code demonstrates CS8764:
public class B
{
public virtual string GetMessage(string id) => string.Empty;
}
public class D : B
{
public override string? GetMessage(string? id) => default;
}
The preceding example shows a virtual
method in a base class and an override
with different nullability. The base class returns a non-nullable string, but the derived class returns a nullable string. If the string
and string?
are reversed, it would be allowed because the derived class is more restrictive. Similarly, parameter declarations should match. Parameters in the override method can allow null even when the base class doesn't.
Other situations can generate these warnings. You have a mismatch in an interface method declaration and the implementation of that method. Or a delegate type and the expression for that delegate differ. A type parameter and the type argument differ in nullability.
To fix these warnings, update the appropriate declaration.
The preceding sections discussed how you can use Attributes for nullable static analysis to inform the compiler about the null semantics of your code. The compiler warns you if the code doesn't adhere to the promises of that attribute:
[NotNull]
or [DisallowNull]
[DoesNotReturn]
should not return.[DoesNotReturn]
annotation to match implemented or overridden member.Consider the following method:
public bool TryGetMessage(int id, [NotNullWhen(true)] out string? message)
{
message = null;
return true;
}
The compiler produces a warning because the message
parameter is assigned null
and the method returns true
. The NotNullWhen
attribute indicates that shouldn't happen.
To address these warnings, update your code so it matches the expectations of the attributes applied. You can change the attributes, or the algorithm.
Switch expressions must be exhaustive, meaning that all input values must be handled. Even for non-nullable reference types, the null
value must be accounted for. The compiler issues warnings when the null value isn't handled:
The following example code demonstrates this condition:
int AsScale(string status) =>
status switch
{
"Red" => 0,
"Yellow" => 5,
"Green" => 10,
{ } => -1
};
The input expression is a string
, not a string?
. The compiler still generates this warning. The { }
pattern handles all non-null values, but doesn't match null
. To address these errors, you can either add an explicit null
case, or replace the { }
with the _
(discard) pattern. The discard pattern matches null in addition to any other value.
Toote „.NET“ tagasiside
.NET on avatud lähtekoodiga projekt. Tagasiside andmiseks valige link:
Sündmused
17. märts, 21 - 21. märts, 10
Liituge sarjaga, et luua muude arendajate ja ekspertidega skaleeritavad tehisintellektilahendused, mis põhinevad reaalajas kasutusjuhtumitel.
Registreeruge kohe