ReSharper 9: first look at C# 6.0 support
Today we want to share some details on our progress in supporting the new language features coming in C# 6.0. While most of the changes in C# 6.0 are relatively small, they will definitely affect the existing ReSharper actions, quick-fixes, refactorings and code inspections. Let’s take a look at some of the new C# features and how ReSharper will help you work with them.
Conditional access
The conditional access expression, also known as the ‘null-propagating’ operator is a small syntax sugar, designed to help dealing with null values. Despite the popular myth, it can’t really magically save you from NullReferenceException once and for all. However, the conditional access operator can dramatically reduce the amount of code needed in some scenarios to check for null values. Consider this method from the ReSharper source code:
Code like this is used extremely often in ReSharper development, since IDE tooling deals with incomplete code almost all of the time. We have to write a lot of code just to handle broken syntax and semantic trees. But most of the time you just need to returnfalse/null to exit method early — and here is when the operator ?. is simply invaluable:
As you could always expect, ReSharper has deep knowledge on how the new language construct behave, how it evaluates, what values it may produce, and whether or not parts of the expression are reachable during the execution:
We also notify you if the conditional access is redundant and offer a quick-fix to replace it with normal non-conditional member access:
But the most interesting part of the ReSharper support for C# 6.0 are transformations. Since tons of C# code had been written before the ? operator was even designed, it is natural for ReSharper to be able to recognize null-propagating code patterns and suggest using the new conditional expression when it matters:
We reviewed a lot of various code snippets to recognize and formalize the patterns, which were then used to implement context actions and suggestions, as well as reverse transformations:
We are even considering a small refactoring action to easily upgrade usages of popular extension methods like .IfNotNull(x => …) by implementing the conditional expressions for earlier C# versions:
The conditional access operator is a great addition to the C# language: it doesn’t affect the language too much, you are not forced to use it, but when you really need the null-propagating code – it provides a nice way of keeping your code clean and concise.
Expression-bodied members
We are super excited by this C# 6.0 language feature. It is designed to reduce the amount of boilerplate code required to declare trivial type members, especially the get-only properties. C# developers might be a bit tired of writing explicit accessors, multiple curly braces and return statements just to yield some values from properties. C# 6.0 solves this problem in a great way with the familiar lambda-expressions syntax:
As you can see, ReSharper is here to help you migrate your code to idiomatic C# 6.0, also being able to apply the transformations file-, project- and solution-wide. Expression bodies are also available for method, indexer and user-defined operator declarations.
Improvements on auto-properties
Besides introducing new language constructs, C# 6.0 aims on making some existing features more useful and covering more user scenarios. For example, auto-properties in C# 6.0 can have initializer expression, just like fields and field-like events:
ReSharper already knows about it and suggests you the transformation even if the backing field is declared readonly and has an initializer expression. Also, you may notice that ReSharper creates auto-property without the set accessor — which is also allowed in C# 6.0 to give you the experience of truly immutable auto-properties, just like readonly fields.
Primary constructors
This feature has been trending on Roslyn forums for months. Primary constructors are designed to make your initialization code more declarative and trivial, to move away from imperative error-prone initialization code in constructor. This feature also improves usability of field/property initializers – they are not allowed to make use of this reference, but constructor parameters are in the scope now. So a typical data class from the example above transforms into the following form:
Unfortunately, C# design team decided not to provide any way of automatic declaration of fields or properties from primary constructor parameter declarations, so you still need to repeat mentioning types and names when declaring property and field members. But there is still room for future design improvements and we hope that the current design is just an incremental improvement before more significant changes are introduced.
Currently, ReSharper recognizes the new primary constructor declaration and the body block syntactically and semantically. The familiar IDE experience, from the extend/shrink selection feature to code completion is available for primary constructors. But of course we want to provide you with the new experience of transforming classes into primary constructor. This is why we’ve built a small analysis engine to inspect the constructor code: ReSharper collects the assignments happening always during the normal constructor execution and tracks type member reads and writes as well as other initializationinformation. The new ReSharper features like ‘Move assignment to initializer’ already have this new engine under the hood (ReSharper 8 has only the reverse ‘Move initialization to constructor’ action) and we are looking forward to use it in primary constructor transformations:
We still have a lot of decisions to make regarding intersections with the existing ReSharper features, and we are still reviewing the feature set that we want to deliver with ReSharper 9. By now, it is unclear how often developers will use this feature, how would they format primary constructor parameters list and so on. Therefore, we would like to hear your opinion on how you expect ReSharper to behave with primary constructor declarations, which transformations and code inspections might be useful to you.
Other changes
We have already supported some other C# 6.0 language features like ‘using static’ (importing of static members of some type in scope) and exception filters (condition clause for catch blocks):
As usual, ReSharper maintains the ‘language level’ concept, enabling different sets of features and inspections for projects targeting any C# compiler version starting from 2.0. We handle everything from the changes in overload resolution between C# versions to small language improvements like await expressions availability in catch/finally clauses oftry block in C# 6.0:
New features like ‘declaration expressions’ (ability to declare variables anywhere inside expressions), dictionary initializers and nameof() operator are on their way.
Looking forward
We should mention that the openness of Roslyn development process helps us a lot. Now we are able to play with the new language and compiler features as early as they are implemented, debug compilers to understand their behavior and even participate in language design discussions. By the way, ReSharper finally successfully compiles with the Roslyn compiler (even while some VB bugs critical for us are still not fixed) and we are looking forward to Visual Studion 14 and Roslyn releases. We expect fast adoption of C# 6.0, since the new language features do not depend on the BCL support and can be used even with .NET Framework 2.0 projects.
In this post we have highlighted only the C# 6.0 bits of upcoming ReSharper 9, just to give you an overview of what we are working on. As usual, we are going to open the EAP as soon as our builds become stable enough. Stay tuned and tell us what you think!
No comments :
Post a Comment