State of the union: ReSharper C# 7 and VB.NET 15 support

When we released ReSharper 2016.3 (and earlier this week, ReSharper 2017.1 EAP), we introduced initial support for C# 7 and VB.NET 15. For example, ReSharper now understands binary literals and digit separators, as well as local functions with several inspections. We’re far from feature complete, but want to look ahead at what’s coming in terms of new programming language features and what we are working on for ReSharper (including some of the challenges building out those features). Here goes!

In this post:

Digit separators and binary literals

Both C# 7 and VB.NET 15 allow _ to occur as a digit separator inside numeric literals. This helps improve code readability. For example, adding digit separators in the following snippet clearly shows our original code may contain a bug (or a bad variable name – naming is hard!)

ReSharper has a quick-fix which lets us add digit separators to any numeric literal:

ReSharper support for C# digit separators

Note that ReSharper adds digit separators at the expected location (thousands separator), but it’s perfectly possible to place them anywhere in a number:

Digit separators also are a language onramp for binary literals. It’s now possible to specify bit patterns directly instead of having to know hexadecimal notation by heart.

ReSharper can easily convert a number to binary notation and back, too:

Binary literals and quick-fix to convert between formats

ReSharper 2016.3 already includes support for C# 7 and VB.NET 15 binary literals and digit separators.

Local functions

When coding, we often have to create a helper function. Sometimes, such helper function should only be available for one single method, so it would make sense to add it inside that method. That’s exactly what local functions are. With C# 7, we can declare helper functions inside other function bodies as a local function:

ReSharper already provides some support for local functions, and provides a basic set of code inspections for them, such as Possible System.NullReferenceException, Access to disposed/modified closure, and more. We also updated some of the existing refactorings and quick-fixes we have, such as this one where we can convert a statement body to an expression body, and back.

Convert local function to expression body and vice-versa

This already existed for C# 6.0, but now it works for C# 7.0 local functions, too. Note in this video we can also see that a recursive call was detected in our local function.

Local functions are comparable to lambda functions, but they are a bit more readable and quite useful if we want to write a function that is called only within the context of another method. In our ReSharper 2017.1 EAP, we added two new quick-fixes that allow converting a lambda expression or anonymous function to a local function:

Convert to local function quick-fix

Our codebase will mature, and the local function may have to become a proper method of its own. No problem! We have you covered on the refactoring front:
Convert local function into a regular method

Support for local functions is still under development. And not only on our side – the language design itself isn’t fully carved in stone either – C# 7.0 is still evolving. For example, we had to wait for a PR from the C# compiler team before we knew whether supporting [NotNull]/[CanBeNull] annotations with local functions to help static analysis would be possible.

Output variables

In C#, using out parameters is not very fluid. For example, we always have to declare a variable with its full type before we can do a method call using that variable:

C# 7 introduces output variables, making it possible to declare a variable right at the point where we’re making our method call:

While ReSharper 2016.3 already recognizes output variables, there are some things we’re improving. An example would be detection of output variable scope. In the above code snippet, the variable number becomes available in the outer scope. This means we can use the number variable outside of our if statement as well. With a loop like for, foreach or while, this does not happen though.

We keep a very close eye on the .NET repo on GitHub to make sure we’ll have fantastic C# 7 support in ReSharper!

Other things we are working on are navigation to the out var‘s type – navigation to out variable itself already works in ReSharper 2016.3.

C# and VB.NET Tuples

What options are there today to return more than one value from a method? We can use out parameters, but they are not very pleasant to work with and not supported when writing async methods. We can use System.Tuple<...> as a return type, but those allocate an object. On top of that, consuming code then has to put up with knowing what the Item1, Item2 etc. properties mean. Specific types or anonymous types are two other options, but those are not very efficient to write/run either.

Both C# 7 and VB.NET 15 now adds tuple return types and tuple literals. For example:

Or in VB.NET:

The calling code will get back a tuple with two string properties, which we can then work with:

That’s… nice, but not very. We’re still using Item1 and Item2 here. Again, C# 7 and VB.NET 15 to the rescue! We can update our FindPersonName method and name our tuple elements:

The consuming code could now look like this:

Much better! We’re building support for tuples in ReSharper, adding and updating inspections, quick-fixes and refactorings. One of those refactorings is Transform parameters”, where we will allow converting a method utilizing out parameters to a method using multiple return values via tuples. As with all new language features, some of them are still moving targets. For example if C# adds support for tuples in using directive, we will, too. To be continued!

Deconstruction

In the above example with tuples, we are still using an intermediate tuple, personNames, which we’re then assigning to a firstName and lastName local variable. C# 7 introduces deconstruction – a clean way of consuming tuples. New syntax has been introduced for splitting a tuple into its parts and assigning those parts to new variables:

Deconstruction not only works for tuples. It works for any type, as long as that type implements the Deconstruct method, either directly or via an extension method. For example, we could write an extension method for KeyValuePair<TKey, TValue> which lets us use the key and value directly – avoiding having to use .Key/.Value expressions.

We can add multiple overloads for the Deconstruct method, taking a different number of out parameters. This lets us support deconstructing into various different variable sets.

ReSharper currently does not support deconstruction yet.

Pattern matching

This is one feature I personally like a lot. C# 7 adds new syntactic elements that allow us to test whether a variable has a certain “shape” or type and then start working with it. Here’s an example:

In the above sample, we are doing several pattern matches. A constant pattern match checks whether data is null. The next two checks are type pattern matches, testing data has a certain type and immediately extracting the value into a new variable with that type. Nice, no? Variables introduced by a pattern are similar to output variables described in that they can be declared in the middle of an expression and can then be used within the nearest surrounding scope.

Another nice example where we’re using patterns and output variables together to check, cast and parse all at once:

ReSharper 2016.3 already partially supports pattern matching for is expressions and switch statements, although we’re still working on supporting a really nice feature of pattern matching where we can write code that checks for type information as well as specific property values using the when keyword:

ReSharper does not yet fully understand this syntax – we’re working on that and looking at making our existing code inspections and quick-fixes aware of new C# 7 syntax. We’ll have to recognize x is null as a null check, suggest using an is expression instead of an as + null check, …

Others

C# 7 and VB.NET 15 come with some additional language enhancements that we’re also adding support for in ReSharper but are still in early stages in our nightly builds (nightlies, one of the perks of working at JetBrains!)

We’re working on properly parsing throw expressions and wiring this into existing inspections, quick-fixes and refactorings.

In our code we could already pass variables by reference (using ref / ByRef). C# 7.0 and VB.NET 15 now also let us return from a method by reference.

Support for ref / ByRef returns is something we’re working on, too.

Many of our existing features have to be adapted or even rethinked to work with a new language version (and of course, should remain compatible with older language versions). We need to make sure existing ReSharper suggestions and inspections still make sense and produce correct and idiomatic C# code.

Our C# 7.0 and VB.NET 15 support is definitely not complete yet. We did want to provide an overview of what the programming language is evolving to and what we are currently working on in terms of supporting that. With ReSharper 2016.3, we provide early support for:

  •  C# 7.0/VB.NET 15 binary literals and digit separators (parsing, several context actions, support for literals written in different base/separated differently)
  • Support for C# local functions (parsing, analyzing null)
  • Limited support for C# pattern-matching expressions (as the language design itself is not finished), C# output variables, C# tuples and C# deconstruction

All work in progress, but if you are using any of the new language features we’d love to hear your feedback! Download ReSharper Ultimate 2016.3, or even ReSharper Ultimate 2017.1 EAP, and give it a try!

This entry was posted in How-To's and tagged , , , , , , . Bookmark the permalink.

10 Responses to State of the union: ReSharper C# 7 and VB.NET 15 support

  1. Pingback: How ReSharper currently supports C# 7 and VB 15, and what's ahead - How to Code .NET

  2. Pingback: State of the union: ReSharper C# 7 and VB.NET 15 support  | OPC Diary

  3. Where does this sit on the Rider side of things? Is the same R# 2017.1 EAP functionality available in Rider too or will that lag behind the R# releases as the team finalizes the C#7 feature-set.

    Also, any word on migrating .NET Core projects over to the new MSBuild project format? We run Core on Macs, would be really great not to have to spin up VMs and install Windows+VS+R# just to move over to the new project format.

    PS: Great work team!

    • Maarten Balliauw says:

      Thanks! :-)

      The latest Rider EAP indeed has the same C# 7 functionality as ReSharper 2017.1. You can try writing, for example, a local function. Rider will detect this is a C# 7 feature and provide a quick-fix “Enable C# 7 support for this project”.

      As for VS2017/msbuild project format, you can follow progress here: https://youtrack.jetbrains.com/issue/RIDER-3777

  4. Pingback: Dew Drop - February 20, 2017 (#2425) - Morning Dew

  5. Pingback: The state of ReSharper support for local functions and other C# 7 and VB 15 features - How to Code .NET

  6. smad says:

    2017.1 Eap 2 still have old logo from 2016.3.
    https://www.screencast.com/t/O3xlI03ggmN

  7. obe says:

    Any chance to get multi-caret support in ReSharper?

    That would be awesome.

  8. Kornel says:

    It’s been a while now since the release of VS 2017 RTM. Is an update to R# with full support of C# 7.0 coming soon?

    Lack of the throw-if-null feature is getting cumbersome with nearly all constructors indicating error
    (_something = something ?? throw new NullArgumentException)

Leave a Reply

Your email address will not be published. Required fields are marked *