生文字列リテラルを使ってみた (C# 11 新機能)

# 生文字列リテラルを使ってみた (C# 11 新機能)

C# 11 で導入された新機能のうち、生文字列リテラルと呼ばれるものが待ち望んでいたものだったので、試してみました。
詳細は以下のMicrosoftによる解説をご確認ください。

https://docs.microsoft.com/ja-jp/dotnet/csharp/whats-new/csharp-11

:::note warn
注意
C# 11 は~~現時点ではプレビュー版です。~~ 2022年11月に正式リリースされました。
~~生文字列リテラルを使用するにはプレビュー版のVisual StudioとSDKの導入が必要です(後述)。~~
~~また、正式リリース版で機能内容が変更されたり、削除されたりする可能性があるそうです。~~
:::

## 生文字列リテラル

生文字列リテラルはMicrosoftによる解説で以下のように説明されています。

> 生文字列リテラルには、エスケープ シーケンスを必要とせずに、空白文字、改行、埋め込み引用符、その他の特殊文字を含む任意のテキストを含めることができます。
> [未加工の文字列リテラル : C# 11 の新機能 - C# ガイド | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/csharp/whats-new/csharp-11#raw-string-literals)

個人的には、複数行の文字列をリテラルとして宣言する場合に、より自然な記述が行える点で有用だと考えています。
以下のようなSQL(SELECT文)を変数に格納する場合を例に挙げます。

```sql:サンプルSQL
SELECT Id, Name
  FROM TableName
 WHERE Id = @id
```

生文字列リテラルを利用して、上記サンプルSQLを表現すると以下のようになります。

```csharp: 生文字列リテラル (例)
string query = """
    SELECT Id, Name
      FROM TableName
     WHERE Id = @id
    """;
```

```:格納文字列 (生文字列リテラル)
SELECT Id, Name
  FROM TableName
 WHERE Id = @id
```

生文字列リテラルは以下のような特徴を持ちます。

* 3つ以上の二重引用符(`"""`)で囲む [^1]
* 開始の引用符(`"""`)の直後の改行と最終行の改行は文字列に含まれない
* 終了の引用符(`"""`)より左側にある空白は文字列に含めない [^2]
* `"` や `\` 等の特殊記号をエスケープせずに含められる

3つ目の *終了の引用符より左側にある空白は文字列に含めない* というのは文字ではわかりづらいと思いますが、図で表すと以下のようになります。
![20220731_0001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1240814/9be49b66-03ec-d801-7f8d-4978c8f54fe8.png)

[^1]: 開始と終了とで二重引用符の数を揃えていれば、4つ以上連ねても問題ありません。
文字列に `"""` が含まれる場合、文字列を囲む引用符を4つ以上にすることで、エスケープせずに `"""` が設定可能となります。
[^2]: 終了の引用符(`"""`)の先頭部分より左側に空白以外の文字列が含まれていると、コンパイルエラーとなります。

### 逐語的文字列リテラルとの違い

逐語的識別子(`@`)を付与した文字列リテラルも、`\`のエスケープが不要になったり文字列中に改行を含められる等、生文字列リテラルと似た特徴を持ちますが、先述した生文字列リテラルの特徴の2つ目と3つ目が大きく異なります。

逐語的文字列リテラルで同じような書き方をすると、実際に格納される文字列は以下のように想定したものとは異なる結果となります。[^3]

```csharp: 逐語的文字列リテラル (例1)
string query = @"
    SELECT Id, Name
      FROM TableName
     WHERE Id = @id
    ";
```

```:格納文字列 (逐語的文字列リテラル)

                SELECT Id, Name
                  FROM TableName
                 WHERE Id = @id
                
```

[^3]: 二重引用符(`"`) で囲まれた範囲にある改行や空白が全てそのまま文字列として扱われる為。

逐語的文字列リテラルで当初の想定通りのSQLを文字列として格納する為には、以下のようにする必要があります。 [^4]

```csharp: 逐語的文字列リテラル (例2)
string query3 = @"SELECT Id, Name
  FROM TableName
 WHERE Id = @id";
```

[^4]: 前後の改行と、インデントにあたる空白を削除した。

実際に変数や定数を宣言するのはクラスやメソッドの内部となる為、以下のようにインデントが大きく崩れる要因となります。
※ 個人的にはこれが不満でした(これが生文字列リテラルで解決されたというわけです)。

```csharp: 逐語的文字列リテラル (例3)
namespace SampleApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string query = @"SELECT Id, Name
  FROM TableName
 WHERE Id = @id";
            // 以下、後続処理
        }
    }
}
```

### 文字列補間 との組み合わせ

以下のように 生文字列リテラル は 文字列補完(`$`) と組み合わせることが可能です(詳細は割愛します)。

```csharp: 文字列補間との組み合わせ (例)
int id = 1234;
string query = $"""
    SELECT Id, Name
      FROM TableName
     WHERE Id = '{id}'
    """;
```


## プレビュー版の導入

~~先述の通り C# 11 が現在はプレビュー版となっている為、通常では 生文字列リテラル は使用できません。~~
~~以下の方法で、プレビュー版の Visual Studio と .NET 7.0 SDK を導入して動作確認を行いました。~~

:::note info
(2022.11.30 追記)
C# 11 が 2022年11月8日に正式リリースされました。
Version 17.4 以降の Visual Studio 2022 で C# 11 が利用可能です。
以下はプレビュー版の導入方法の覚え書きとして残しておきます。
:::

:::note alert
(2022.11.30 追記)
プレビュー版の .NET 7.0 SDK をインストールした場合、Visual Studio 2022 をアップデートすると既存のプロジェクトが開けなくなります。
プレビュー版をアンインストールする必要がありますのでご注意ください(以下の記事が参考になりました)。
参考：[VisualStudio2022をアップデートしたら、プロジェクトが開けないし、新規作成もできなくなった - Qiita](https://qiita.com/ShTair/items/aa4c37c3a3f23ee98433)
:::

### プレビュー版の Visual Studio 

以下のページから プレビュー版の Visual Studio をダウンロードして、インストールします。
※ 通常の Visual Studio のダウンロードリンクの下に、プレビュー版のダウンロードリンクが置かれています(`Download Community 2022 Preview` 等)。

https://docs.microsoft.com/ja-jp/visualstudio/releases/2022/release-notes-preview

### .NET 7.0 SDK

:::note warn
(2022.11.30 追記)
.NET 7.0 SDK が正式版となった為、プレビュー版は現時点でダウンロードできなくなっています。
:::

以下のページから .NET 7.0 の Visual Studio 2022 SDK をダウンロードして、インストールします。

https://dotnet.microsoft.com/ja-jp/download/visual-studio-sdks

### プロジェクト設定

Visual Studio でプロジェクトのプロパティを開き、.NET 7.0 を使用するように変更します。

* アプリケーション > 全般 > ターゲット フレームワーク : `.NET 7.0`

プロジェクトファイル(*.csproj) をエディタで開き、コンパイル時に C# 11 の構文が受け付けられるように、`LangVersion` に `preview` を設定します。
(既に `LangVersion` が設定されている場合、値を `preview` に変更します)

```xml
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <LangVersion>preview</LangVersion> <!-- 左記を追加/変更 -->
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
</Project>
```

以上で設定を行ったプロジェクトで生文字列リテラル(を含む C# 11 の新しい機能)が利用できるようになると思われます。