Talking about C #6.0 improvement from NullObject,
Preface
In this article, we will talk about the null check problems we often do, from a simple null check Any Where, to the design pattern NullObjectPattern, the syntax provided by C #6.0 "possibly" allows us to experience the "continuous improvement" in language development and Let's go ~
What is an empty reference exception?
As a code farmer who has been coding, it seems that no one has ever encountered the NullReferenceException problem. Sometimes, when a property or method (delegate) is called inside a method, we control the performance of these attributes in "external" (except for the ref keyword in some cases, of course ), therefore, we need to judge the attribute inside the method and whether the delegate method is Null to avoid possible Null reference exceptions caused by incorrect use, so that when we know that if the object is Null, we will achieve what we expected.
Null reference exception solved --- Check Any Where
This is very simple. I only need to check if it is Null where I need it. Yes, this is very simple and the semantics is clear, but when you want to repeat an object for 100 million times, there will be 10000 code segments in your code:
public void Check() { if (Person.AlivePerson() != null) { Person.AlivePerson().KeepAlive = true; } }
Can you tolerate such behavior?
If (OK)
Continue;
Else
Close;
Apply the NullObject Design Pattern
NullObjectPattern comes from forth by Gamma (four-person group in the design mode). The core content is to provide a null value proxy for a given object, and the null value proxy provides a method to do nothing.
Next let's take a look at the C # implementation on Wikipedia:
// compile as Console Application, requires C# 3.0 or higherusing System;using System.Linq;namespace MyExtensionWithExample { public static class StringExtensions { public static int SafeGetLength(this string valueOrNull) { return (valueOrNull ?? string.Empty).Length; } } public static class Program { // define some strings static readonly string[] strings = new [] { "Mr X.", "Katrien Duck", null, "Q" }; // write the total length of all the strings in the array public static void Main(string[] args) { var query = from text in strings select text.SafeGetLength(); // no need to do any checks here Console.WriteLine(query.Sum()); // The output will be: 18 } }}
In the C # language, we use static extension methods to unify the inspection methods within the method, rather than writing everywhere, in the above example, A SafeGetLength extension method is implemented on the String class, which provides a method for all String types, so that we take another step in "code clean.
Next let's look at a more common example-from StackOverFlow
public static class EventExtensions { public static void Raise<T>(this EventHandler<T> evnt, object sender, T args) where T : EventArgs { if (evnt != null) { evnt(sender, args); } } }
Finally, let's talk about a detailed problem. None of the above Code implements "thread security". In the article by Eric Lippert, we have had a better discussion about thread security. Please click here.
The improved Code adds a temporary variable inside the method as a copy of the method to implement thread security, if you have any questions, refer to the performance of internal method variables on the stack in my C # stack vs stack.
public class SomeClass { public event EventHandler<EventArgs> MyEvent; private void DoSomething() { var tmp = MyEvent; MyEvent.Raise(this, EventArgs.Empty); } }
More "tidal" approach-C #6.0 syntax
Mark Michaelis (author of C # Essence) from MSDN Magazine introduced the possible improvements of C #6.0 in language, there are improvements to the "Null condition operator.
C #6.0 for more information:
Part One: https://msdn.microsoft.com/zh-cn/magazine/dn683793.aspx
Part Two: https://msdn.microsoft.com/zh-cn/magazine/dn802602.aspx
Even a beginner in. NET development may be very familiar with NullReferenceException. One exception is that a Bug is almost always pointed out, because the developer did not perform a full null check before calling a member 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 { result = value.Substring(0, Math.Min(value.Length, length)); } return result;}
If null check is not performed, this method will cause NullReferenceException. Although this is simple, it is a little complicated to check whether the string parameter is null. Generally, considering the frequency of comparison, this tedious method may not be necessary. C #6.0 includes a new null condition operator to help you write these checks more easily:
public static string Truncate(string value, int length){ return value?.Substring(0, Math.Min(value.Length, length));}[TestMethod]public void Truncate_WithNull_ReturnsNull(){ Assert.AreEqual<string>(null, Truncate(null, 42));}
According to the content demonstrated by the Truncate_WithNull_ReturnsNull method, if the object value is actually null, the null condition operator returns null. This brings up a problem, that is, what happens when the null condition operator appears in the call chain? As shown in the following example:
public static string AdjustWidth(string value, int length){ return value?.Substring(0, Math.Min(value.Length, length)).PadRight(length);}[TestMethod]public void AdjustWidth_GivenInigoMontoya42_ReturnsInigoMontoyaExtended(){ Assert.AreEqual<int>(42, AdjustWidth("Inigo Montoya", 42).Length);}
Although Substring is called through the null condition operator, and null value ?. Substring seems to return null, but the language behavior is based on your idea. This simplifies the PadRight call process and immediately returns null, so as to avoid NullReferenceException programming errors. This concept is called "null propagation ".
The Null condition operator checks null Based on specific conditions, and then calls the target method and all other methods in the call chain. This may produce a surprising result, such as text ?. The result in the Length. GetType statement.
If the null condition operator returns null when the call target is null, what data type will be returned when the call returns a type member (assuming that the value type cannot be null )? For example, from value ?. The data type returned by Length cannot be int. The answer is of course: it can be a null type (int ?). In fact, if you try to allocate only the result to int, a compilation error will occur:
int length = text?.Length; // Compile Error: Cannot implicitly convert type 'int?' to 'int'
The Null condition has two syntax forms. First, the question mark is before the vertex operator (?.). Secondly, the question mark and index operator are used in combination. For example, if you specify a set (instead of explicitly performing the null check before the index reaches the Set), you can use the null condition operator to perform this operation:
public static IEnumerable<T> GetValueTypeItems<T>( IList<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 the operator? […] In the form of null Condition Index, resulting in indexing to the set only when the set is not null. Using the null condition operator, T? Item = collection? The [index] statement is equivalent:
T? Item = (collection! = Null )? Collection [index]: null.
Note that the null condition operator can only retrieve projects and does not allocate projects. If a null set is given, what does this mean?
Are you sure you want to use it for reference types? […] . Since the reference type can be null, is the set null or is the element itself actually null? […] The null result of the operator is not clear.
A very useful application of the Null condition operator solves a feature that has always existed in C # Since C #1.0, that is, to check whether it is null before calling the delegate. Let's take a look.FigureC #2.0 code displayed in.
Figure 1 check whether the delegate is Null before calling
class Theremostat{ event EventHandler<float> OnTemperatureChanged; private int _Temperature; public int Temperature { get { return _Temperature; } set { // If there are any subscribers, then // notify them of changes in temperature EventHandler<float> localOnChanged = OnTemperatureChanged; if (localOnChanged != null) { _Temperature = value; // Call subscribers localOnChanged(this, value); } } }}
By using the null condition operator, the entire set implementation process can be simplified:
OnTemperatureChanged?.Invoke(this, value)
Now, you only need to call the Invoke with the null condition operator as the prefix, and do not need to assign the delegate instance to the local variable to implement thread security, or even explicitly check whether the value is null before calling the delegate.
C # developers are eager to know whether the content has been improved in the latest four versions. The answer is that the improvements are finally made. Only this function can change the way the delegate is called.
Another common mode for the popularization of null condition operators is to be used with coalesce operators. You do not need to perform a null check on linesOfCode before calling Length. Instead, you can write a project counting algorithm, as shown below:
List<string> linesOfCode = ParseSourceCodeFile("Program.cs");return linesOfCode?.Count ?? 0;
In this case, any empty set (no project) and null set are normalized to return the same number. In short, the null condition operator implements the following functions:
1.If the operand is null, null is returned.
2.If the operand is null, other calls in the call chain are simplified.
3.If the target member returns a value type, the return value can be a null type (System. Nullable <T> ).
4.Support for delegated calls in thread-Safe Mode
5.Can be used as a member operator (?.) And the index operator (? […])
Download Sample Code
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 condition Operator
Http://en.wikipedia.org/wiki/Null_Object_pattern --- explanation of NullObjectPattern on Wikipedia