C# 6.0 support in ReSharper 9.1
One of the interesting challenges in creating an IDE is tracking changes to a language as it evolves. ReSharper 9.0 shipped with early support for C# 6.0, but the language wasn’t done yet. Now that the design is stable, the recently released ReSharper 9.1 provides full support for the new language features. It obviously understands the new syntax, but also includes new functionality to take advantage of the changes in C# and to help bring your code up to date with the new language version.
In many respects, C# 6.0 is an incremental update to the language. There are no major features like LINQ or async/await. Instead, we have a number of syntax changes that reduce some of the boilerplate and ceremony of writing C#. Put together, these new features allow us to write code that is terser, shorter and easier to read.
Let’s take a look at how ReSharper supports some of these features.
C# 6.0 adds two new features to auto-properties – you can make them getter only, and provide initializers for them. A getter only auto-property is different to a property with a private setter in that it is immutable. A private setter can be called from anywhere else in the class, but a read-only auto-property can only be set in the constructor, or via a property initializer, much like a field can be initialized where it’s declared.
ReSharper’s inspections spot when a property’s setter is only called from the constructor, and marks the unused setter as dead code. A quick Alt+Enter, and we’ve got a read-only auto-property:
While static methods are very useful, it can get a little verbose constantly having to qualify them with their class name. The ‘using static’ feature allows you to import the class in much the same way as you import a namespace. Once imported, you can access static members of that class without having to specify the class name. ReSharper offers Context Actions to easily import a class from the Alt+Enter menu, shows when qualifying the class name is redundant, and offers bulk cleanup:
Conditional access expressions
This is likely to be C# 6.0’s best loved feature. Null references are a fact of life to C# developers, and “if” statements have been the only way to handle them so far. The new conditional access operator “?.” will replace many of these null checks. Unlike the normal “.” dot access operator, the conditional access operator will not throw an exception if the preceding expression is null. Instead, it returns null and stops evaluating the rest of the expression. This is going to have a huge, positive impact on your codebase.
And of course, ReSharper understands how this operator (and indeed, the other changes to C# 6.0) affects the control flow of your code, and can use that to warn about possible null references, or redundant conditional access:
The nameof operator
C# is a nice, strongly-typed language. Usually, the compiler will check that we’re using valid type and member names, but this falls down sometimes, when we have to use “magic strings”, such as the argument name to ArgumentNullException, or a typename to Reflection, or property names for INotifyPropertyChanged. The compiler won’t check these values, and it’s easy to introduce errors, especially when we rename a type or member.
To help with these problems, ReSharper can resolve the argument name in ArgumentNullException, and has had extensive support for INotifyPropertyChanged since version 7. C# 5 introduced caller information attributes, and now C# 6.0 introduces a more generic mechanism – the nameof operator.
Instead of typing the name of a type or member as an opaque, constant string literal, you can now use the nameof operator and refer to the type or member as a symbol, and take advantage of C#’s strong typing, and compiler checking. If the symbol in the nameof operator is unknown, the compiler reports it as an error. And since it’s a symbol, ReSharper can include it in Find Usages, renames and will even provide suggestions to convert magic strings to usages of nameof:
This feature is intended to make it easier to format strings. On the face of it, string.Format isn’t exactly difficult, but again, it’s not type-safe. It relies on the order of format specifiers in a string, and the arguments passed being correct. If the order is wrong, the formatting is wrong, but you’ll only discover this at runtime. String interpolation provides a solution by specifying expressions inline, inside the format string. There’s no chance for mismatched specifiers and arguments, and no excuse for getting things in the wrong order.
ReSharper provides an inspection to convert string.Format calls to string interpolation, and naturally provides code completion and find usages and rename for members used in the expressions inside the interpolated strings:
Another feature designed to reduce the amount of boilerplate in your code. You can now define simple properties and methods using a lambda-like syntax, rather than wrapping the code in braces and newlines. They’re exactly the same as regular methods and getter only properties, but take less keystrokes. And, yes, we mean Alt+Enter.
The real power of these features comes out when we combine them. Take this example. ReSharper shows us a suggestion that the null check can be replaced by the conditional access operator. Alt+Enter can quickly fix this up for us, and give us a simple return statement. Alt+Enter again invokes the “To expression body” context action, and we’ve now very quickly moved from a multi-line method to a simple, readable, single line method:
But what happens if you’ve got a C# 5.0 project, and you want to use the lovely new C# 6.0 features? By default, ReSharper won’t allow or suggest using new features for a project targeting an older version of the compiler. You can change the supported language level in the Properties window when the project is selected in Solution Explorer. Or take the easy route – if ReSharper complains that you’re using a newer feature, just use Alt+Enter to change the supported language level:
And of course, ReSharper understands the other changes to C# 6.0, such as dictionary initializers, exception filters and using await in catch/finally. The new C# 6.0 support requires Visual Studio 2015, and ReSharper 9.1, part of the ReSharper Ultimate suite of .NET tools.