// New language features in C# 6.0 // From: https://msdn.microsoft.com/en-gb/magazine/dn802602.aspx #define NULLCOND #undef AUTO_PROP_INIT #undef NAME_OF_EXPR #undef PRIMARY_CONSTR #undef EXPR_BODIED_FCTS #if NULLCOND // ----------------------------------------------------------------------------- // Null-Conditional Operator using System; //using Microsoft.VisualStudio.TestTools.UnitTesting; public class Test { public static string Truncate0(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; } 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(null, Truncate(null, 42)); } 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(42, AdjustWidth("Inigo Montoya", 42).Length); } */ // ----------------------------------------------------------------------------- // Figure 1 Checking for Null Before Invoking a Delegate // ----------------------------------------------------------------------------- public static void Main () { string str1 = "this is a very long string"; string str2 = "short"; string tr_str1 = Truncate(str1, 10); Console.WriteLine("The string '{0}' has been truncated to 10 characters, giving '{1}'", str1, tr_str1); } } #endif #if AGAIN class Theremostat { event EventHandler OnTemperatureChanged; private int _Temperature; public int Temperature { get { return _Temperature; } set { // If there are any subscribers, then // notify them of changes in temperature EventHandler localOnChanged = OnTemperatureChanged; if (localOnChanged != null) { _Temperature = value; // Call subscribers localOnChanged(this, value); } } } // Leveraging the null-conditional operator, the entire set implementation is reduced to simply: // OnTemperatureChanged?.Invoke(this, value) } #endif // ----------------------------------------------------------------------------- // Auto-property initialisers #if AUTO_PROP_INIT // The auto-property initializer allows assignment of properties directly within their declaration. For read-only properties, it takes care of all the ceremony required to ensure the property is immutable. Consider, for example, the FingerPrint class in this example: public class FingerPrint { public DateTime TimeStamp { get; } = DateTime.UtcNow; public string User { get; } = System.Security.Principal.WindowsPrincipal.Current.Identity.Name; public string Process { get; } = System.Diagnostics.Process.GetCurrentProcess().ProcessName; } #endif // ----------------------------------------------------------------------------- // NameOf expressions (reflection) #if NAME_OF_EXPR // Figure 2 Extracting the Parameter Name with a Nameof Expression public class TestNameOf { void ThrowArgumentNullExceptionUsingNameOf(string param1) { throw new ArgumentNullException(nameof(param1)); // here we use the nameof reflection mechanism to get the name of the param } [TestMethod] public void NameOf_UsingNameofExpressionInArgumentNullException() { try { ThrowArgumentNullExceptionUsingNameOf("data"); Assert.Fail("This code should not be reached"); } catch (ArgumentNullException exception) { Assert.AreEqual("param1", exception.ParamName); } } #endif // ----------------------------------------------------------------------------- // Primary Constructors #if PRIMARY_CONSTR public class TestPrimaryConstr { // Consider, for example, the immutable Pair data structure shown in this example: struct Pair(T first, T second) { public T First { get; } = first; public T Second { get; } = second; // Equality operator ... } } /* The constructor definition—Pair(string first, string second)—is merged into the class declaration. This specifies the constructor parameters are first and second (each of type T). Those parameters are also referenced in the property initializers and assigned to their corresponding properties. When you observe the simplicity of this class definition, its support for immutability and the requisite constructor (initializer for all properties/fields), you see how it helps you code correctly. That leads to a significant improvement in a common pattern that previously required unnecessary verbosity. */ #endif // ----------------------------------------------------------------------------- // Expression Bodied Functions and Properties #if EXPR_BODIED_FCTS public class TestFcts { /* Expression bodied functions are another syntax simplification in C# 6.0. These are functions with no statement body. Instead, you implement them with an expression following the function declaration. */ // For example, an override of ToString could be added to the Pair class: public override string ToString() => string.Format("{0}, {1}", First, Second); } #endif