How-To's

Introduce variable, iterate and merge back deconstruction

In our previous post, we’ve looked more closely at and how ReSharper 2018.1 and Rider 2018.1 help maintain consistency when using deconstructing declarations and discards. This time, let’s check out how ReSharper (and Rider) can assist us with introducing variables, iterating and merging back deconstruction when writing new or updating existing C# code.

Introducing variables with deconstruction

Introduce variable is arguably the most used refactoring that has ever existed in ReSharper, and which was available since the very first versions. It allows us to create a new variable, initialize it with a selected expression and optionally replace other occurrences of the same expression with the newly introduced variable.

ReSharper 2018.1 brings an improvement to it: whenever we invoke introduce variable on a tuple or any other expression whose type supports deconstruction, we now get the choice to either introduce a single variable, or to deconstruct the given expression into multiple variables. And if it’s possible to deconstruct value in several ways, ReSharper will show all the alternatives:

Introduce variable demo

Hint: we can introduce a variable in different ways. Via Refactor This… in the Alt+Enter menu, by hitting Ctrl+R,V, by invoking the .var postfix template or by executing the Introduce variable context action.

In the example above, we have three deconstruction choices. Let’s see why! The return type of our method GetPackage is a tuple, so we can deconstruct it into two variables. The second component of our tuple has the type Package, which has a custom deconstructor method defined – hence the second alternative. Remember that deconstructors can be defined not only as instance methods, but as extension methods as well, allowing us to add deconstruction capabilities to external classes.

public class Package
{
  public string Name { get; }
  public string Author { get; }
  public Version LatestVersion { get; }

  public Package(string name, string author, Version latestVersion)
  {
    Name = name;
    Author = author;
    LatestVersion = latestVersion;
  }

  public void Deconstruct(out string name, out string author, out Version latestVersion)
  {
    name = Name;
    author = Author;
    latestVersion = LatestVersion;
  }
}

We can go even deeper, because the property Package.LatestVersion is of type Version, which in its turn is deconstructible as well – that brings us to the last option!

public class Version
{
  public int Major { get; }
  public int Minor { get; }
  public int Build { get; }

  public Version(int major, int minor, int build)
  {
    Major = major;
    Minor = minor;
    Build = build;
  }

  public void Deconstruct(out int major, out int minor, out int build)
  {
    major = Major;
    minor = Minor;
    build = Build;
  }
}

Note that some types can be deconstructed in a large number of ways. In such cases, ReSharper tries hard to avoid combinatorial explosion and limits the space of variations.

Iterating with deconstruction

For quite a long time already, ReSharper has been providing a neat way to generate loops over collections: the .foreach postfix template!

Similar to the introduce variable refactoring, it has received remarkable improvements: when collection items are of a deconstructible type, ReSharper allows us to select between introducing a single iterator variable or deconstructing the item into components. Let’s slightly modify the previous example and watch the .foreach postfix template in action!

Foreach template demo

Deconstructing and merging back

Last but not least, let’s take a look at how we can deal with existing code. For those situations, ReSharper provides two new context actions: Deconstruct variable and its counterpart Merge deconstructed declaration. The first one, as the name implies, takes a variable declaration of deconstructible type, replaces it with a deconstructing declaration and updates original usages of that variable.

It’s worth to mention, that if the context action cannot find any usage of a certain component, it will insert a discard into deconstructing declaration instead of declaring a variable. On the other hand, the Merge deconstructed declaration context action is doing the exact opposite: given a deconstructed declaration, the action replaces it with a single variable declaration and rewrites the usages of every original variable. What’s really nice about this context action is that it can transform the whole declaration at once, going recursively through deeply nested deconstructions. But enough words – seeing is believing!

Deconstruct and merge demo

As we have seen in the previous posts, ReSharper 2018.1 and Rider 2018.1 provide a number of new features that truly embrace the deconstruction and let us be more productive while writing code!

Download ReSharper 2018.1 now! Or give Rider 2018.1 a try. We’d love to hear your thoughts!

image description