Introduction
Visual Studio 2015 was released on July 20, 2015 and with it came a new version of C#. This article is one of two that introduces the new features in C# 6.
Nameof Operator
Sometimes your code needs to reference the name of a variable or method. For example, consider the following method.
Listing 1.1: Hard coding a variable name.
public string MakeAllCaps(string s)
{
if (s == null)
throw new ArgumentNullException("s");
return s.ToUpper();
}
The code in Listing 1.1 throws an exception if the argument s is null. To provide more detailed error information to the user, this code passes the name of the parameter (argument) that was null to the exception class.
The problem, however, is that it is conceivable that the developers could, over time, change the name of the method's parameters. If a developer changes the name for s but forgets to change the string passed to the ArgumentNullException constructor, the code will compile and run without errors. But the information about the argument that was null will be wrong. Listing 1.2 shows how the Nameof operator can help here.
Listing 1.2: Using the Nameof operator to reference a variable name.
public string MakeAllCaps(string s)
{
if (s == null)
throw new ArgumentNullException(nameof(s));
return s.ToUpper();
}
This version of the code uses the Nameof operator to specify the name of the method's argument. Now if a developer changes the name for s, they will need to also change the argument to the Nameof operator. However, unlike before, they will get a compile-time error if they forget to do that. Moreover, they can use the Visual Studio IDE to refactor the name of this argument, which will automatically change the variable name everywhere it is used.
Null-Conditional Operator
Consider the line of C# code in Listing 2.1.
Listing 2.1: An example of accessing a chain of members.
string phone = Product.Company.PhoneNumbers.FirstOrDefault().Number;
You've probably seen code similar to this. But what happens if Product could be null? You'll just need to add a test for this case, and only attempt to access Company once you confirm that Product is not null.
Such a test is very simple, but it does take a bit more typing and can make it a little harder to read. But the bigger problem here is that Company might also be null. In fact, maybe PhoneNumbers could be null also. And, certainly, FirstOrDefault() could return null. All of a sudden, this very simple task becomes a little bit of a pain.
Listing 2.2: An example of accessing a chain of members using the Null-Conditional operator.
string phone = Product?.Company?.PhoneNumbers?.FirstOrDefault()?.Number;
Listing 2.2 uses the Null-Conditional operator (?.) to streamline the code. The Null-Conditional operator does not throw a null-reference exception. If the object on the left of the operator is null, then the entire expression will return null. So the revised code is perfectly safe as long as you test the final value against null.
Note that, in order for your code to be able to determine if anything in the chain was null, the final result must always be a nullable value. This has ramifications if you are accessing a non-nullable type. Consider the code in Listing 2.3. While String.IndexOf() returns int, this code will return int? (nullable integer) when accessed via the Null-Conditional operator. This allows your code to test for null, which would signify that s was null.
Listing 2.3: The final result of the Null-Conditional operator must always be nullable.
int? i = s?.IndexOf('x');
Finally, a slightly modified form of the Null-Conditional operator can be used with the index operator when accessing an element of an object that could be null.
Listing 2.4: Using the Null-Conditional operator with the index operator
int? i = myArray?[3];
Here, i will be safely (no exception) set to null if myArray is null.
Auto-Property Initializers
Listing 3.1 shows how public properties were created with early versions of C#. It required a private variable to store the property value, and then a public property to expose that value.
Listing 3.1: Implementing properties the old way.
class Test
{
private string _myString;
public string MyString
{
get
{
return _myString;
}
set
{
_myString = value;
}
}
The code above required a bit of typing, and some of it seems kind of redundant. And so C# 3.0 added support for auto properties. Listing 3.2 demonstrates implementing the same code as above, except it uses the get and set keywords to automatically generate a public property.
Listing 3.2: Example of an auto property.
class Test
{
public string MyString { get; set; }
}
Now C# 6.0 extends auto properties with auto-property initializers, as shown in Listing 3.3.
Listing 3.3: Example of an auto-property initializer.
class Test
{
public string MyString { get; set; } = String.Empty;
}
As shown above, auto-property initializers allow you to use the short-hand syntax of auto properties and still assign an initial value to the property just as you would assign an initial value to any other variable. Also note that the initialized value expression is not a compile-time constant. The assignment can include more complex expressions.
Auto-property initializers have also been extended to provide a nice shortcut for creating and initializing read-only properties, as shown in Listing 3.4.
Listing 3.4: Example of a getter-only auto-property initializer.
class Test
{
public string MyString { get; } = String.Empty;
}
A related change was also added to allow getter-only properties to be initialized from the constructor. Previously, you could not set the value of a getter-only property because they were read-only. These properties are still read-only except now with the exception of within the class' constructor. This is demonstrated in Listing 3.5.
Listing 3.5: Example of initializing a getter-only auto-property from the constructor.
class Test
{
public string MyString { get; }
public Test()
{
MyString = String.Empty;
}
}
Support for auto-property initializers was going to be extended even further in C# 6.0 with primary constructors. After all, if you are initializing your public properties using auto-property initializers, it might make sense to initialize them this way with values passed to your constructor. Primary constructors would allow you to define constructor arguments before the body of a class, and then use those arguments as auto-property initializers. Unfortunately, this feature was pulled at the last minute from the final release of C# 6.0. Keep an eye out for primary constructors in a future release.
Conclusion
To read about more new features in C# 6, please see the article What's New in C# 6 (Part 2).
End-User License
Use of this article and any related source code or other files is governed
by the terms and conditions of
.
Author Information
Jonathan Wood
I'm a software/website developer working out of the greater Salt Lake City area in Utah. I've developed many websites including Black Belt Coder, Insider Articles, and others.