Page 22 - MSDN Magazine, February 2018
P. 22

ments to reduce nullable idiosyncrasy. The fact of the matter is that today, string text; results in a reference type called text that allows text to be null, expects text to be null, and, in fact, defaults text to be null in many cases, such as with a field or array. However, just as with value types, reference types that allow null should be the exception—not the default. It would be preferable if when we assigned null to text or failed to initialize text to something other than null, the compiler would flag any dereference of the text variable (the compiler already flags dereferencing a local variable before it’s initialized).
Unfortunately, this means changing the language and issuing a warning when you assign null (string text = null, for example) or assign a nullable reference type (such as string? text = null; string moreText = text;). The first of these (string text = null) is a breaking change. (Issuing a warning for something that previously incurred no warning is a breaking change.) To avoid overwhelming devel- opers with warnings as soon as they start using the C# 8.0 compiler, instead Nullability support will be turned off by default—thus no breaking change. To take advantage of it, therefore, you’ll need to opt-in by enabling the feature. (Note, however, that in the pre- view available at the time of this writing, itl.tc/csnrtp, Nullability is on by default.)
Support for nullable reference types should decrease the likelihood of throwing a NullReferenceException, though not eliminate it.
Of course, once the feature is enabled, the warnings will appear, presenting you with the choice. Choose explicitly whether the ref- erence type is intended to allow nulls, or not. If it’s not, then remove the null assignment, thus removing the warning. However, this potentially introduces a warning later on because the variable isn’t assigned and you’ll need to assign it a non-null value. Alternatively, if null is explicitly intended (representing “unknown” for example), then change the declaration type to be nullable, as in:
string? text = null;
Decrease the Occurrence of NullReferenceExceptions
Given a way to declare types as either nullable or non-nullable, it’s now up to the compiler’s static flow analysis to determine when the declaration is potentially violated. While either declaring a refer- ence type as nullable or avoiding a null assignment to a non-nul- lable type will work, new warnings or errors may appear later on in the code. As already mentioned, non-nullable reference types will cause an error later on in the code if the local variable is never assigned (this was true for local variables before C# 8.0). In con- trast, the static flow analysis will flag any dereference invocation of a nullable type for which it can’t detect a prior check for null and/
Figure 1 Examples of Static Flow Analysis Results
or any assignment of the nullable value to a value other than null. Figure 1 shows some examples.
Either way, the end result is a decrease in potential NullReference- Exceptions by using static flow analysis to verify a nullable intent. As discussed earlier, the static flow analysis should flag when a non-nullable type will potentially be assigned null—either directly or when assigned a nullable type. Unfortunately, this isn’t foolproof. For example, if a method declares that it returns a non-nullable reference type (perhaps a library that hasn’t yet been updated with nullability modifiers) or one that mistaken- ly returns null (perhaps a warning was ignored), or a non-fatal exception occurs and an expected assignment doesn’t execute, it’s still possible that a non-nullable reference type could end up with a null value. That’s unfortunate, but support for nullable reference types should decrease the likelihood of throwing a NullReferenceException, though not eliminate it. (This is analogous to the fallibility of the compiler’s check when a variable is assigned.) Similarly, the static flow analysis won’t always recognize that the code, in fact, does check for null before dereferencing a value. In fact, the flow analysis only checks the nullability within a method body of locals and parameters, and leverages method and opera- tor signatures to determine validity. It doesn’t, for example, delve into the body of a method called IsNullOrEmpty to run analysis on whether that method successfully checks for null such that no
additional null check is required.
Enable Suppression of Static Flow Analysis Warning
Given the possible fallibility of the static flow analysis, what if your check for null (perhaps with a call such as object.Reference- Equals(s, null) or string.IsNullOrEmpty()) is not recognized by the compiler? When the programmer knows better that a value isn’t going to be null, they can dereference following the ! operator (for example, text!) as in:
string? text;
...
if(object.ReferenceEquals(text, null)) {
var type = text!.GetType() }
Without the exclamation point, the compiler will warn of a possible null invocation. Similarly, when assigning a nullable value to a non-nullable value you can decorate the assigned value with an exclamation point to inform the compiler that you, the pro- grammer, know better:
string moreText = text!;
In this way, you can override the static flow analysis just like you can use an explicit cast. Of course, at runtime the appropriate verification will still occur.
string text1 = null;
// Warning: Cannot convert null to non-nullable reference string? text2 = null;
string text3 = text2;
// Warning: Possible null reference assignment Console.WriteLine( text2.Length );
// Warning: Possible dereference of a null reference if(text2 != null) { Console.WriteLine( text2.Length); } // Allowed given check for null
18 msdn magazine
Essential .NET


































































































   20   21   22   23   24