Embrace deconstruction with ReSharper 2018.1
Deconstruction is a great feature that was introduced with C# 7. A while ago, we showed how ReSharper (and Rider) can help generate deconstructors for us. ReSharper 2018.1 adds even more enhanced support to fully embrace the elegance and power of deconstructions with new code styles, quick-fixes, context actions, better refactoring support and more!
In the next two posts, we’ll go over these new features. This first post is dedicated to new code styles. The second part will cover everything else. Let’s dive in!
Deconstruction is a way of a decomposing tuple (or any other value whose type has a deconstructor) into parts. The decomposed parts can be assigned either to fresh variables — deconstructing declaration or to existing variables – deconstructing assignment.
Deconstructing declaration, unlike assignment, can be expressed using two slightly different syntaxes.
The first, more concise, syntax puts the
var outside of the parentheses and tells the compiler to infer types of every deconstructed variable:
// 'personInfo' is variable of type '(string, string, int)' var (firstName, lastName, age) = personInfo;
The second syntax uses separate declarations for each deconstructed variable and allows either to specify variable type explicitly or use
(string firstName, string lastName, int age) = personInfo; // explicitly typed variables (var firstName, var lastName, var age) = personInfo; // implicitly typed variables (string firstName, string lastName, var age) = personInfo; // mixed typing
The nice thing about deconstructions is that they can be nested, i.e. whenever a decomposed part is a tuple itself (or of type with custom deconstructor), we can deconstruct it right within outer deconstructing declaration.
Not every deconstruction syntax can be used together, namely if we put
var outside of parentheses, then neither explicit types nor
vars should be used inside:
// 'keyValuePair' is variable of type '(long, (string, string, int))' (long id, (string firstName, string lastName, int age)) = keyValuePair; // ok var (id, (firstName, lastName, age)) = keyValuePair; // ok (long id, var (firstName, lastName, age)) = keyValuePair; // ok var (id, (var firstName, var lastName, var age)) = keyValuePair; // error var (id, var (firstName, lastName, age)) = keyValuePair; // error
In order to make deconstructing declarations consistent across the code base, ReSharper 2018.1 introduces the new code style setting Prefer separate declarations for deconstructed variables. Note that plain old ‘var’ Usage in Declarations code style is applied only when separate declarations are preferred.
Once configured, ReSharper highlights deconstructing declarations that are not following the code style, and suggests quick-fixes Use single deconstruction declaration or Use separate declaration expressions. Needless to say that quick-fixes can also be applied in scope of file, current project or the whole solution. And as always, ReSharper provides accompanying context actions which allow us to switch between alternative syntaxes.
Sometimes, when deconstructing a value, we only care about a subset of its components. In such cases, irrelevant components can be ignored using the discards feature of C#, expressed as
_ (a single underscore):
(string firstName, string lastName, var _) = personInfo; // 'age' is discarded (var firstName, var _, _) = personInfo; // 'lastName' and 'age' are discarded var (firstName, _, _) = personInfo; // 'lastName' and 'age' are discarded
Because C# 7 allows us to optionally omit the type of discarded variables, ReSharper 2018.1 adds one more code style setting – Use ‘var’ keyword for discards – to configure whether
var _is preferred over
_. The same code style is also applied to discards used as
outparameters. For any inconsistencies found, ReSharper suggests to apply quick-fixes Remove redundant ‘var’ keyword or Use explicit discard declarations.
Stay tuned for our next post, where we explore more possibilities around deconstruction!