今日は「実は Visual Studio 17.1 Preview 1 (先月) の時点で既に入ってた」という機能の話。

C# 11 で、$"{ここ}" みたいな「補完穴」(interpolation hole: 補完文字列の {} の中)の改行に関する仕様がちょっと変わります。

文字列リテラル中の改行

C# の文字列リテラルは、@ を付けると逐語的(\ を使ったエスケープをしなくなる)になって、その中には改行を直接入れることができます。

// @ を付けると文字列内での改行 OK になる。

var s1 = ""; // 改行入れれない。
var s2 = @"
"; // 改行 OK。
var s3 = "
"; // 当然これはコンパイル エラー。

この仕様、補間文字列に対しても同様です。

// @ を付けると文字列内での改行 OK になるのは $"" でも一緒。

var x = 123;

var s1 = $"{x}"; // 改行入れれない。
var s2 = @$"
{x}
"; // 改行 OK。
var s3 = $"{x}
"; // 当然これはコンパイル エラー。

補間穴中の改行

C# はほぼ全ての構文で改行の有無を問わないので、例えば以下の2つのコードは全く同じ意味になります。

var x = 123 + 987;
var
    x
    =
    123
    +
    987
    ;

で、補間穴 ({})の中は普通の C# 構文になります。 前述のような「改行の有無を問わない」という常識に照らし合わせると、 以下のようなコードを書けていいはずです。 (C# 10 まではなぜかダメ。)

// なぜかダメだったコード。

var x = 123;

var s1 = $"{
    x
    }";

ちなみに、これに @ を付けると C# 10 でもコンパイルできます。 というか、さらに言うと割かし何でも書けます。 // コメントすら書けます。

// @ を付ければなぜか OK。

var x = 123;

var s1 = $@"{
    x
    +
    987 // コメントすら OK
    }";

C# 11 での変更

で、まあ、$"{}"$@"{}" で挙動が違うの、 仕様的にもそうなってるらしいんですが、 中の人曰く「改行を禁止した実際の理由、覚えてない」とのこと。

挙動が違うのも変なのでさらっと直したみたいです。 気づいたタイミング的に C# 10 正式リリースには間に合わなかったものの、 ほぼ修正は終わってたみたいで、即座に merge、実は 17.1 Preview 1 には入っていたみたいです。

ということで、実は LangVersion preview を入れればもう動くらしい。

LangVersion preview を入れればもう動くらしい

(このスクショは Visual Studio 17.1.0 Preview 1.1 で撮影。)

さよなら、LangVersion default。おかえり、preview (1年ぶり2度目)。

ということで、以下のようなコード、C# 11 候補になっていて、 preview 指定すると現在でもコンパイルできたりします。

// C# 11 候補。

var x = 123;

var s1 = $"こっちは C# 11 から OK {
    x
    +
    987 // コメントすら OK
    }";

var s2 = $@"こっちは元から OK
{
    x
    +
    987 // コメントすら OK
    }
def";

と言うのを昨日の Pull Request を見て初めて気づいたという話でした。