Strange behaviour of String Interpolation Refactorings in VisualStudio 2015/Roslyn/Resharper

We switched to VisualStudio 2015 at work a few days ago, using Resharper inside as before. VisualStudio has some great new features in this version, a few bugs, and some strange behaviours I don’t understand.

In some articles I’m going to talk about some strange refactoring suggestions I discovered, starting with string interpolations here.

Just to ask beforehand: Is there any way to identify where a refactoring comes from (is it a suggestion and/or implementation of Roslyn or Resharper?)

String interpolation is a new feature in C#6. It’s pure syntactic sugar and I’m not even sure if I like it or not. Basically any string.Format() invocation can be written as a string interpolation „literal“ instead. A good introduction on string interpolations I found in the C#/.NET Little wonders, further explanations are given e.g. in the Tales from the evil empire.

In short: The compiler generates the corresponding string.Format() command as a replacement for the interpolation „literal“ to create the same IL code for runtime.

Connected to this new language feature I found some quirks in how Visual studio behaves:

„Use string interpolation expression“ refactoring

The following code uses string.Format() in three cases. I know that it’s stupid to replace a constant format string with compile time constant parameters, but it’s valid:

switch (i)
{
  case 1: 
    throw new Exception(string.Format(
      "to {0} or not to be", 
      "be"));
  case 2: 
    throw new Exception(
      string.Format(
        "to {0} or not to {1}", 
        "be", 
        "be"));
  case 3: 
    throw new Exception(
      string.Format(
        "to {0} or not to {0}", 
        "code"));
}

Ignore the switch/case structure and concentrate on the string.Format invocation. Interestingly the case I want to document here doesn’t work with string.Format alone, but I’m not sure where exactly it behaves this way.

The first and the second string.Format command in that code block are underlined in green in my Visual Studio, indicating a refactoring suggestion. Automatic refactorings are possible at nearly any code element usually; but the green underline indicator should suggest it were be a good idea (which it not always is in fact).

In this case the tooltip on it says „Use string interpolation expression“. After applying that, the code looks like this:

switch (i)
{
  case 1: 
    throw new Exception(
      $"to {"be"} or not to be");
  case 2: 
    throw new Exception(
      $"to {"be"} or not to {"be"}");
  case 3: 
    throw new Exception(
      string.Format(
        "to {0} or not to {0}", 
        "code"));
}

This is correct code again – it looks even less complex (to be honest, the interpolation parantheses around „be“ have a different style in Visual studio, so it’s not entirely invisible that there’s more than a pure string literal behind).

But that’s the case I want to point out: This refactoring is completely stupid!

If it’s final code, there’s a much better alternative, one that is even available (although not proposed by the green underlining) as a refactoring as well:

„Evaluate Expression“ refactoring

The „Evaluate Expression“ refactoring is does a real replacement of the format string, removing the additional cost of string.Format and producing much cleaner code:

switch (i)
{
  case 1: 
    throw new Exception("to be or not to be");
  case 2: 
    throw new Exception("to be or not to be");
  case 3: 
    throw new Exception("to code or not to code");
}

Expression evaluation would not have been possible for parameters that are not compile time constant, as these may change at runtime, but in my example code from the beginning we are talking about compile time constant parameters, so that this would have been the better replacement – if at all.

Drawbacks of string interpolations

The drawback of string interpolation in general is in my opinion the hurden for posterior localization efforts: When you want to replace a yet constant string from code by some lookup mechanism for localization to enable switching the language on program startup or even during runtime, string interpolations have to be reverted as – see above – it’s basically syntactic sugar for string.Format(). For the translatable string the interpolation placeholders therefore have to be replaced back to the numeric placeholders as used in string.Format(), so you have to undo the refactoring before you can copy and past the string from the source code to your localization resource.

Conclusion

String interpolation might be a nice feature. It reduces the cognitive workload when you have many parameters in format string, as what’s inside the string is directly visible in place (under the assumption of slightly meaningful variable naming of course).

The refactoring towards string interpolations is given too often in my opinion.

As a side node: There is the construct of „verbatim string literals“ as well. Prefixed with an @, like in @“foo“ the difference to „usual“ string literals in resharper is that in verbatim strings less characters are taken into account for replacement: Tabs, Newlines and so on are taken as written in the code and don’t have to be encoded as \t, \n etc.

As described in a StackOverflow answer of RobH to a related question, ReSharper can be configured to ignore verbatim strings for localization suggestions. If that’s the case, it would be much better to propose refactorings towards string interpolations if and only if strings are verbatim string literals, as in any other case strings should be possible internationalization „tasks“.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.