ネコのために鐘は鳴る

寺院に住み着くパソコ〇好き

(C#) 文字列補間されていない文字列補間を取得する

明日使えない小ネタ記事です。

 

C# 10 から文字列補間の $"" 構文が独自拡張可能になっています。 これはパターンベースになっており、特定の条件を満たす型を書くことで動作します。

本記事ではまともな使い方やメリットについては解説しません。 まともな使い方や実装方法は公式ドキュメントを見てください。

これをハックして、文字列補間前の文字列を取得してみます。 以下のような型を作ります。

using System.Runtime.CompilerServices;

[InterpolatedStringHandler]
public readonly struct NotInterpolation
{
    public string Value { get; }
    public NotInterpolation(
        int literalLength,
        int formattedCount,
        [CallerArgumentExpression("literalLength")] string expr = "")
    {
        Value = expr;
    }
    public void AppendLiteral(string s) { }
    public void AppendFormatted<T>(T t) { }
    public override string ToString() => Value;
}

そして以下のコードを実行。

var num = 10;
NotInterpolation str = $"The number is {num}.";
Console.WriteLine(str.Value);

実行結果の出力がこちら

$"The number is {num}."

文字列ハンドラーのコンストラクタの第一引数に対して CallerArgumentExpression 属性で引数表現を取ると、なんとびっくり文字列補間前の文字列表現が文字列で取れるんです。 パターンベースなので、コンストラクタに勝手に引数を追加してもデフォルト引数があればコンパイルできちゃうんです。

しかも、この文字列表現はコンパイル時に確定しておりハンドラー自体は構造体なので最適化されて全てが消えるため、実行時コストは0です。嬉しい~~~。

 

何に使えるんだ……これ?