はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【C#】C#11から登場した生文字列リテラル(Raw String Literal)を利用してT4の実行時テンプレートを脱却する

はじめに

今回はC#11より登場した生文字列リテラル(Raw String Literal)を紹介したいと思います。

// サンプル
public static void Main()
{
    var name = "Hanachiru";
            
    // C#11より登場した生文字列リテラル (T4の実行時テンプレートの移行先としてしばしば利用される)
    var sampleClass = $$"""
public class SampleClass
{
    public static void SampleMethod()
    {
        Console.WriteLine("Hello, {{name}}!");
    }    
}
""";
            
    // ファイル書き込み
    const string path = "/Users/.../SampleClass.cs";
    using var writer = new StreamWriter(path, false, Encoding.UTF8);
    writer.Write(sampleClass);
}
// 生成されたコード
public class SampleClass
{
    public static void SampleMethod()
    {
        Console.WriteLine("Hello, Hanachiru!");
    }    
}

概要

生文字列リテラル(Raw String Literal)は、エスケープシーケンスを必要とせずに複数行の文字列リテラルを記述することができます。

生文字列リテラル は、文字列リテラルの新しい形式です。 生文字列リテラルには、エスケープ シーケンスを必要とせずに、空白文字、改行、埋め込み引用符、その他の特殊文字を含む任意のテキストを含めることができます。

C# 11 の新機能 - C# ガイド - C# | Microsoft Learn

// サンプル
var name = "Hanachiru";

var sampleClass = $$"""
public class SampleClass
{
    public static void SampleMethod()
    {
        Console.WriteLine("Hello, {{name}}!");
    }    
}
""";

最初と最後の「"""」

Raw String Literalを利用する場合は開始・終わりに3つ以上の「"を用意する必要があります。このとき最初と最後で数は同じにしてください。

public class Test
{
    public void Hoge()
    {
        var a = """
aaa
bbb
""";
        var b = """"
aaa
bbb
"""";

        var c = """"""""""
aaa
bbb
"""""""""";
    }
}

なぜ3つ以上に増やすようにしたかというと、中に"""が入っている場合に対応するためですね。

public class Test
{
    public void Hoge()
    {
        var c = """"""""""
"""ここは普通の文字列として扱ってほしい"""
"""""ここも普通の文字列として扱ってほしい"""""
"""""""""";
    }
}

インデント

生文字列リテラルには以下の制約があります。

  • 開始と終了の両方の引用符文字(例. """)は、独自の行に配置する必要がある
  • 終了引用符の左側にある空白はすべて、生文字列リテラルのすべての行から削除される

生文字列リテラル - """ - C# | Microsoft Learn

つまり、最後の"""(終了引用符)よりも左側にある空白は、すべての行で無視されます。

namespace SampleConsole
{
    internal class Program
    {
        public static void Main()
        {
            var sampleClass = """
                public class SampleClass
                {
                    public static void SampleMethod()
                    {
                        Console.WriteLine("Hello, World!");
                    }    
                }
                """;
        }
    }
}
// 対応した文字列
public class SampleClass
{
    public static void SampleMethod()
    {
        Console.WriteLine("Hello, World!");
    }    
}

ちなみに終了引用符よりも左に文字を書くとエラーがちゃんと出力してくれます。

Line does not start with the same whitespace as closing line of the raw string literal

補間された生文字リテラル

生文字列リテラルに変数を埋め込むためには開始引用符(例. """)の前に$を一つ以上記述し、変数を埋め込む箇所に$の数と同じ{}で囲ってあげます。

var name = "Hanachiru";

var a = $"""
Console.WriteLine({name});
""";
            
var b = $$"""
Console.WriteLine({{name}});
""";
            
var c = $$$$$$"""
Console.WriteLine({{{{{{name}}}}}});
""";

$が一つ以上なのはなぜかと思うかもしれませんが、引用符文字が3つ以上である理由と同じです。

var b = $$"""
Console.WriteLine("{" + {name}});
""";
            
var c = $$$$$$"""
Console.WriteLine("{{{{" + {{{{{{name}}}}}});
""";