7 C# 6.0 Features That Every ASP.NET Developer Should Know About

Visual Studio 2015 introduces a completely new version of ASP.NET, but it also includes version 6 of the C# language. Previous new versions of C# have heralded substantial changes like the introduction of async and await in version 5, dynamic in version 4, LINQ in version 3 and so on. There are no major feature changes or introductions in version 6, but there are a number of syntactical improvements that you are likely to use on a daily basis. Here's a rundown of them.

I will start with a pair of classes that might form a very simple model in any application:

public class Person
{
    public Person()
    {
        FirstName = string.Empty;
        LastName = string.Empty;
        DateCreated = DateTime.UtcNow;
        Qualifications = new HashSet<Qualification>();
    }
    public int PersonId { get; set; }
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string FullName { get { return string.Format("{0} {1}", FirstName, LastName); } }
    public DateTime DateCreated { get; set; } 
    public DateTime BirthDate { get; set; }
    public ICollection<Qualification> Qualifications { get; set; } 
}
public class Qualification
{
    public Qualification()
    {
        Awardees = new HashSet<Person>();
        Name = string.Empty;
    }
    public int QualificationId { get; set; }
    public string Name { get; set; } 
    public DateTime WhenAwarded { get; set; }
    public virtual ICollection<Person> Awardees { get; set; } 
}

The model features a Person class and a Qualification class, and a many-to-many relationship between them. The associations between the classes are declared as virtual, indicating that they are navigation properties in a Code First model intended for use with Entity Framework. Auto properties have largely been used because there is no logic to be executed when setting or getting the property values. The FullName property in the Person class is constructed from the FirstName and LastName properties. Default values for some properties are defined in class constructors. The first three new C# 6 features are all concerned with improving syntax when defining simple classes like these. I will look at how they affect the Person class.

1. Auto-property initializers

If you want to set a default value for a property in a class, you do this in the constructor in C# 5 or less. C# 6 introduces Auto-property initializers that enable you to assign a default value for a property as part of the property declaration. This is how using auto-property initializers changes the look of the Person class:

public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
    public string FullName { get { return string.Format("{0} {1}", FirstName, LastName); } }
    public DateTime DateCreated { get; set; } = DateTime.UtcNow;
    public DateTime BirthDate { get; set; }
    public ICollection<Qualification> Qualifications { get; set; } = new HashSet<Qualification>();
}

2. Expression bodied members

The FullName property in the Person class is readonly. There is no set accessor for the property. The value is generated from an expression in the get accessor. In C# 6, this expression can be used in the same way as the auto-property initializer, reducing the syntax down a bit:

public string FullName => string.Format("{0} {1}", FirstName, LastName);

The => sign does not denote a lambda expression in the same way as if it is being used with LINQ or any other delegate-based scenario. You can also use this approach to define the body of a method. For example, you might choose to expose a person's age as a method called GetAge() like this:

public TimeSpan GetAge()
{
    return DateTime.Now - BirthDate;
}

You can now replace this with an expression body function like so:

public TimeSpan GetAge() => DateTime.Now - BirthDate;

3. Getter-only auto-properties

When you use auto implemented properties in C# 5 and lower, you must provide a get and set. If you want the property value to be immutable, you can use the private accessor on the setter, but that has always been considered to be a bit of a hack. With C# 6, you can now omit the set accessor to achieve true readonly auto implemented properties:

public DateTime BirthDate { get; }

4. String interpolation

Up until now, I have used string.Format to generate the FullName value in the Person class. I've always found string.Format a little clumsy to use although I would prefer to use it rather than have bunch of concatenation operators dotted around my code. A new feature named string interpolation provides a large improvement (in my opinion) in this area. Rather than filling placeholders with indexes then provide an array of values to be slotted in at runtime, you provide the source of the parameter value instead, and the string.Format call is replaced by a single $ sign. This is how the FullName property declaration looks when using string interpolation in the expression body instead:

public string FullName => $"{FirstName} {LastName}";

Apart from this saving a number of key strokes, it should also minimise (if not remove) the possibility of FormatExceptions being generated from inadvertently supplying too few values to the argument list.

5. Null-conditional operators

var people = new List<Person>();
var name = string.Empty;
if(people.FirstOrDefault() != null)
{
    name = people.First().FullName;
}

How many times have you written code that checks for null to prevent a possible NullReferenceException when attempting to reference a member on an object? If the answer is "way too many", you will probably grow to love the null conditional operator, which is a simple question mark ? placed just before member you want to reference:

var people = new List<Person>();
var name = people.FirstOrDefault()?.FullName;

If people.FirstOrDefault() returns null, evaluation is terminated without any exceptions being raised, and null is assigned to the name variable. Now that's a useful addition to the language! One thing to be aware of - if you assign a value type to an expression that uses a null conditional operator, the result will be a nullable type.

6. Using static

I'm not sure I've made my mind up about this one. But here it is. This feature provides a shortcut to accessing static methods on classes by importing the name of the class via a using directive qualified by the static keyword. For example, this is how you would do that with the System.IO.File class, which includes quite a number of static utility methods:

using static System.IO.File;

Now you can use the static methods without having to use the class name:

var file = @"C:\test.txt";
if (!Exists(file))
{
    Create(file);
}

The System.Text.RegularExpressions.Regex class also houses a range of static methods:

using static System.Text.RegularExpressions.Regex;
...
...
Replace("input", "pattern", "replacement");

I'm not entirely sure what problem this feature is intended to solve. Chances are that I will forget to use this at all. Utility method names are very similar - Replace, Create, Delete, and if you are using Regex and File (as an example) in the same file, you will find yourself having to disambiguate between methods across classes that have the same name and signature (like Replace).

7. Index initializers

This feature provides a new way to initialize index-based collections such as dictionaries. Previously, you might do this:

Dictionary<int, string> dict = new Dictionary<int, string>
{
    {1, "string1" },
    {2, "string2" },
    {3, "string3" }
};

Now you can do this:

Dictionary<int, string> dict = new Dictionary<int, string>
{
    [1] = "string1",
    [2] = "string2",
    [3] = "string3" 
};

Apart from this blog post, I wonder if I'll ever get to use this new feature.

Summary

This post has reviewed most of the new features in C# 6 that the average ASP.NET developer is most likely to use or encounter. Personally, I can see myself using the first 5 features regularly, but I am yet to be convinced about the benefits of the last two, and will most likely forget that they are available.