Objective
This article is to talk about the null check problem we often do, from a simple null value to check any where, to the design pattern of the nullobjectpattern, and then to c#6.0 "may" provide the syntax, let's experience a language development on the "continuous improvement", lets ' s go~
What is a null reference exception
As a code-tapping farmer, it seems that no one has ever encountered the problem of NullReferenceException, and sometimes when a method internally invokes a property, Method (delegate), we control the performance of these properties in the "outer" (except in some cases with the REF keyword) , so we have to judge the property in the inside of the method, whether the delegate method is null to avoid possible, incorrect use of the null reference exception, so that when we know that if the object is null, we will achieve in line with our "expected" behavior.
Resolve NULL Reference Exception---Check any Where
It's easy, I just need to check if it's null. Yes, this is very simple and semantically clear, but when you want to double-check an object entity 100 million times, there are 10,000 code snippets in your code:
Public void Check () { ifnull) { true; } }
Can you tolerate such behavior?
If (OK)
Continue;
Else
Close;
Applying Nullobject Design Patterns
Nullobjectpattern from Forth by Gamma (design mode 4-person group), the core content is: to provide a null proxy for a given object, the null agent provides a way to do nothing in the implementation.
Now let's look at the C # implementation on Wikipedia:
//Compile as Console application, requires C # 3.0 or higherusingSystem;usingSystem.Linq;namespaceMyextensionwithexample { Public Static classstringextensions { Public Static intSafegetlength ( This stringvalueornull) { return(Valueornull??string. Empty). Length; } } Public Static classProgram {//define some strings Static ReadOnly string[] strings =New[] {"Mr X.","Katrien Duck",NULL,"Q" }; //Write The total length of the strings in the array Public Static voidMain (string[] args) { varquery = fromTextinchStringsSelectText. Safegetlength ();//no need to does any checks hereConsole.WriteLine (query. Sum ()); //The output would be:18 } }}
In the C # language, we implement a static extension method to unify the inspection method inside the methods, rather than writing them everywhere, the above example implements a Safegetlength extension method on the string class, which provides a method for all string types so that we " Code neat "on another step.
Let's look at a more common example---from StackOverflow
Public Static class eventextensions { publicstaticvoid raise<t> (The Thisobject sender, T args) where t:eventargs { ifnull) { evnt (sender, args); } } }
Finally, to say a detail question, the above code all did not implement "thread safety", in Daniel Eric Lippert's article for thread safety has had a more exciting discussion, please poke here.
The improved code adds a temporary variable inside the method, as a copy of the inside of the method, for thread safety, and if you have questions, refer to the chapter on the stack of the method's internal variables in my C # heap vs stack.
Public class SomeClass { publicevent eventhandler<eventargs> myevent; Private void dosomething () { var tmp = myevent; Myevent.raise (this, eventargs.empty); } }
More "tidal" way to-c#6.0 grammar
Mark Michaelis from MSDN Magazine (author of the C # Nature theory) gave us an introduction to the new improvements that c#6.0 might bring to the language, including improvements to the null conditional operator.
c#6.0 More references:
Part one:https://msdn.microsoft.com/zh-cn/magazine/dn683793.aspx
Part two:https://msdn.microsoft.com/zh-cn/magazine/dn802602.aspx
Even beginners of. NET development may be familiar with NullReferenceException. One exception is the fact that a Bug is almost always pointed out because the developer did not make sufficient null checks before invoking the members of the (null) object. Take a look at the following example:
public static string Truncate (string value, int length) { string result = value; if (value! = null ) // Skip empty string check for elucidation = value. Substring (0 return result;}
This method throws a NullReferenceException if no null check is performed. Although this is simple, the process of checking whether a string parameter is null is a little cumbersome. Often, considering the frequency of comparisons, the tedious approach may not be necessary. C # 6.0 includes a new null-conditional operator that can help you write these checks more easily:
public static string Truncate (string value, int length) { return value?. Substring (0 public void Truncate_withnull_returnsnull () {assert.areequal < string > (null , Truncate (null , 42 );}
Depending on what is demonstrated by the Truncate_withnull_returnsnull method, if the value of the object is actually NULL, the null condition operator returns NULL. This brings up the question of what happens to the null conditional operator when it appears in the call chain? As shown in the following example:
Public Static stringAdjustwidth (stringValueintlength) { returnValue?. Substring (0, Math.min (value. length, length)). PadRight (length);} [TestMethod] Public voidadjustwidth_giveninigomontoya42_returnsinigomontoyaextended () {assert.areequal<int> ( the, Adjustwidth ("Inigo Montoya", the). Length);}
Although Substring is called by the null condition operator, and null value?. Substring seems to return null, but the language behaves as you think. This simplifies the process of calling PadRight and immediately returns NULL, thus avoiding programming errors that can cause NullReferenceException to occur. This concept is called "Null propagation".
The null condition operator makes a null check based on the condition, and then calls the target method and all other methods in the chain. This will likely produce a surprising result, for example, text?. The result in the Length.gettype statement.
If the null condition operator returns NULL when the call target is null, then what is the final data type when the call returns a member of the value type (assuming the value type cannot be null)? For example, from value?. The data type returned by Length cannot be just int. The answer is of course: a nullable type (int?). )。 In fact, attempting to assign only the result to int will cause a compilation error:
int // Compile error:cannot implicitly convert type ' int? ' to ' int '
Null conditions have two syntactic forms. First, the question mark precedes the dot operator (?.). Second, use the question mark and index operators together. For example, given a collection (not an explicit null check before indexing to the collection), you can do this using the null condition operator:
public static ienumerable<t > Getvaluetypeitems<t> <T> collection, params int [] indexes) where T: struct { foreach (int index in indexes) {T ? Item = collection? [index]; if (item! = null ) yield return (T) item; }}
This example uses an operator? [...] The null conditional index form, which causes the collection to be indexed only if the collection is not null. By this form of the null condition operator, T? Item = collection? The [index] statement behaves as follows:
T? Item = (Collection! = null)? Collection[index]: null.
Note that the null condition operator can only retrieve items, and no items will be assigned. If a null collection is given, what does this mean?
Note Use for reference types? [...] Implicit ambiguity of the time. Since the reference type can be null, is it null for the collection, or if the element itself is actually null, from? [...] The null result of the operator is ambiguous.
A very useful application of the Null condition operator solves a feature that C # has existed since C # 1.0, that is, to check for NULL before invoking the delegate. Let's take a look at the C # 2.0 code shown in the figure .
Figure 1 Checking for Null before invoking a delegate
classtheremostat{Eventeventhandler<float>ontemperaturechanged; Private int_temperature; Public intTemperature {Get { return_temperature; } Set { //If There is any subscribers and then//notify them of changes in temperatureeventhandler<float> localonchanged =ontemperaturechanged; if(Localonchanged! =NULL) {_temperature=value; //Call subscribersLocalonchanged ( This, value); } } }}
By using the null condition operator, the entire set implementation process can be simplified to:
Ontemperaturechanged?. Invoke (This, value)
Now, you only need to call invoke with the null conditional operator as the prefix, no longer have to assign the delegate instance to a local variable for thread safety, or even explicitly check whether the value is null before invoking the delegate.
C # developers are interested in knowing whether this content has improved in the latest four releases. The answer is that the improvements were finally made. Only this feature can change the way a delegate is invoked.
Another common pattern that is prevalent with the null conditional operator is in conjunction with the coalesce operator. Instead of a null check on Linesofcode before calling Length, you can write the item count algorithm as follows:
list<string> Linesofcode = Parsesourcecodefile ("Program.cs"); return 0;
In this case, any empty collection (no items) and a null collection are normalized to return the same number. In summary, the null conditional operator implements the following functionality:
1. If the operand is null, NULL is returned
2. If the operand is null, simplify the other calls in the call chain
3. Returns a nullable type (system.nullable<t>) if the target member returns a value type.
4. Support delegate invocation in a thread-safe manner
5. use as the member operator (?.) and index operator (? ...])
Sample code Download
Reference
Http://stackoverflow.com/questions/13629051/net-event-raising-and-nullobject-pattern---Thread-safe extension mechanism
Https://msdn.microsoft.com/zh-cn/magazine/dn802602.aspx---c#6.0 null conditional operator
Http://en.wikipedia.org/wiki/Null_Object_pattern---nullobjectpattern on wikipedia
Talking about c#6.0 improvement from Nullobject