Interpolasi string $"Total: {total}" terlihat seperti sintaks sederhana, tetapi compiler sebenarnya menerjemahkannya menjadi serangkaian pemanggilan method pada sebuah objek penampung yang disebut interpolated string handler. Pola ini bukan rahasia internal: kita bisa membuat handler sendiri, misalnya untuk log yang hanya menyusun teks saat diaktifkan. Bab ini memperkenalkan polanya secara ringkas.
Anatomi sebuah Handler #
Tipe handler ditandai atribut [InterpolatedStringHandler] dan wajib menyediakan konstruktor dengan dua parameter tetap: literalLength (panjang seluruh teks tetap) dan formattedCount (jumlah ekspresi interpolasi). Dua method berikut menampung isinya: AppendLiteral menerima potongan teks tetap, dan AppendFormatted menerima hasil tiap ekspresi interpolasi:
[InterpolatedStringHandler]
public readonly struct CatatanHandler
{
private readonly StringBuilder? _penampung;
public CatatanHandler(int literalLength, int formattedCount, bool aktif, out bool aktifkan)
{
_penampung = aktif ? new StringBuilder(literalLength + 8) : null;
aktifkan = aktif;
}
public void AppendLiteral(string teks) => _penampung?.Append(teks);
public void AppendFormatted<T>(T nilai) => _penampung?.Append(nilai?.ToString());
public string Hasil => _penampung?.ToString() ?? string.Empty;
}Parameter aktif berasal dari method pemanggil, dan out bool aktifkan memberi tahu compiler apakah bagian interpolasi perlu dieksekusi. Bila aktif bernilai false, _penampung tidak dialokasikan, seluruh Append* menjadi no-op, dan string final tidak pernah dibangun.
Dua parameter tetap pada konstruktor punya tujuan praktis: literalLength memungkinkan handler mengalokasikan buffer dengan ukuran awal yang cukup sejak awal, sedangkan formattedCount memberi tahu berapa banyak ekspresi interpolasi yang akan datang. Keduanya dihitung compiler saat kompilasi, sehingga tidak ada penghitungan saat program berjalan.
Memakai Handler pada Method #
Parameter bertipe handler membuat compiler menerima bentuk $"..." langsung di titik pemanggilan. Atribut [InterpolatedStringHandlerArgument] meneruskan parameter lain ke konstruktor handler:
private static void Catat(
bool aktif,
[InterpolatedStringHandlerArgument("aktif")] CatatanHandler handler)
{
string hasil = handler.Hasil;
Console.WriteLine(hasil.Length > 0 ? hasil : "(string tidak dibangun)");
}
Catat(true, $"Total belanja: {45000 + 30000}");
Catat(false, $"Total belanja: {45000 + 30000}");Output yang Dihasilkan:
Total belanja: 75000
(string tidak dibangun)Mari kita telaah apa yang terjadi:
- Pemanggilan pertama: Compiler membangun
CatatanHandlerdenganaktif = true, lalu memanggilAppendLiteral("Total belanja: ")danAppendFormatted(75000); handler menyusun teks lengkapnya. - Pemanggilan kedua: Konstruktor menerima
aktif = falsedan melaporkanaktifkan = false, sehingga compiler melewati seluruh panggilanAppend*dan buffer tidak dialokasikan. - Method
Catat: PropertiHasilmengembalikan string kosong pada pemanggilan kedua, dan program mencetak penanda(string tidak dibangun).
Pola ini layak dibuat bila penyusunan teks mahal atau jarang dibutuhkan: pesan log bertingkat, peringatan debug, atau teks laporan yang hanya aktif pada kondisi tertentu. Untuk interpolasi biasa di dalam program sehari-hari, bentuk $"..." langsung tetap pilihan yang paling sederhana.