static void

C#7 Extras

Published Tuesday 21 February 2017

We've discussed pattern matching and value tuples, the major new features in C#7 / Visual Studio 2017. What else is new?

Remember C#7 isn't the same a .Net version upgrade - you can use these language features in projects targeting .net Core, .net 4.6, 4.5 and even 4.0 (even, sometimes, v2/v3.5).

Deconstruct

You can add a "Deconstruct" method to a class that returns multiple values. It's not an interface (like Dispose), and you can even use an extension method - the Roslyn compiler will find and use it.

public class PagedResult
{
    public List<Product> Products { getset; }
    public int Count { getset; }

    public void Deconstruct(out List<Product> products, out int count)
    {
        products = Products;
        count = Count;
    }
}

Then you can pull out the values in one line.

var (list, count) = page;

This is actually how value tuples work.

It's nice for "hiding" a few simple types - KeyValuePair in a dictionary is a great candidate for Deconstrust. Otherwise, I can't see it being useful for most business classes.

Local functions

Simply, these are methods within methods.

public static void CreateFile(string folder, string name)
{
    EnsureFolderExists(folder); //call local function
    var file = Path.Combine(folder, name);
    File.WriteAllText(file, string.Empty);

    //the local function - never called by anything else
    void EnsureFolderExists(string f)
    {
        if (!Directory.Exists(folder))
        {
            Directory.CreateDirectory(folder);
        }
    }
}

There's no public/private modifier, obviously. Local functions may be useful somewhere in the middle ground between lambdas - which can get unreadably complex quickly - and regular "top level" private methods.

Number literals with separator

Number literals can have a "_" separator to make them a little more readable.

var million = 1_000_000;

The underscore doesn't have to be in the conventional 3 digit positions. Once you use the variable, they are gone and to display it you have to format as normal. Obviously you can't load numbers like that from settings files. I'm struggling to think of a real-life use for this.

More expression-bodies

In C#6 we had "expression-bodied members", using lambdas for simple one-liner properties and methods.

//c#6 expression bodied property
public string Name => FirstName + " " + LastName;
//c#6 expression bodied method
public string FullName() => FirstName + " " + LastName;

Now we have constructors and accessors.

//c#7 expression bodied ctor
public Person(string lastName) => LastName = lastName;

//c#7 expression bodied accessors
public int Age
{
    get => _age; //no "return "
    set => { _age = value; NotifyPropertyChanged(); }
}

You can also throw directly within the expression (and more generally in other places too).

//c#7 expression bodied method with throw
public string Init(string name) 
    => LastName = name ?? throw new ArgumentNullException(nameof(name));

I'm a little wary of expression-bodies. I'm not sure the lambda syntax is easier to read than a couple of braces and line breaks. If the body isn't dead-simple, the temptation is to make unreadable, complex one-liners instead of refactoring to a regular method or property. That said, the constructors syntax is likely to be useful.

Wrap-Up

There are other features like ref returns and binary literals. Overall, most of the features I cover above aren't things you'll use or see every day - or even every week. You can expect to use pattern matching fairly regularly, and value tuples will be useful - in moderation.

C#6 introduced string interpolation, which I find myself using every day. C#7 doesn't have a killer feature of the same calibre, but it's a mixed bag of solid improvements and minor changes.

Previously: C#7 Value Tuples (20 February 2017)