Skip to content

C# UTF-8 String Literals — Complete Guide

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about C# UTF. We cover key concepts, practical examples, and best practices.

You send a string over the network or write it to a stream that expects UTF-8 bytes. You call Encoding.UTF8.GetBytes() on every operation, allocating a new byte array each time. UTF-8 string literals (C# 11) give you compile-time UTF-8 byte representations.

Wrong

string json = "{\"type\": \"ping\"}";
byte[] bytes = Encoding.UTF8.GetBytes(json);
await stream.WriteAsync(bytes);

Output: Works. But GetBytes allocates a byte[] every time. If this is in a hot path, it creates GC pressure.

ReadOnlySpan<byte> json = "{\"type\": \"ping\"}"u8;
await stream.WriteAsync(json);

Output: Same bytes, zero allocation. The u8 suffix tells the compiler to produce a UTF-8 encoded ReadOnlySpan<byte> at compile time.

UTF-8 string literals are stored as static data in the assembly — no runtime encoding, no allocation.

// In expressions
HttpClient.PostAsync(url, new ByteArrayContent("data"u8.ToArray()));

// With raw string literals
ReadOnlySpan<byte> json = """
    { "type": "ping" }
    """u8;

Prevention

  • Use "text"u8 when you need UTF-8 bytes for network I/O, file writes, or interop.
  • Use "text"u8 in hot paths where Encoding.UTF8.GetBytes would allocate.
  • Use raw string literals """..."""u8 for multi-line UTF-8 content.
  • Convert to byte[] with .ToArray() when the API requires it.
  • Store as static readonly byte[] when the same bytes are used repeatedly.
  • Know that u8 always produces ReadOnlySpan<byte> — assign to the right type.

Common Mistakes with utf 8 string

  1. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
  2. Using return to exit a function early instead of wrapping a pure value in the monad
  3. Mixing let bindings with <- bindings in do notation, producing type errors

These mistakes appear frequently in real-world CSHARP code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

What is the type of a u8 literal?

ReadOnlySpan<byte>. You cannot assign it to byte[] directly. Use .ToArray() if you need an array: byte[] data = "hello"u8.ToArray();.

Are u8 literals validated at compile time?

Yes. The compiler validates that the string is valid UTF-8 at compile time. If the string contains invalid surrogates or unpaired surrogates, you get a compiler error — not a runtime exception.

Can I use u8 with string interpolation?

No. String interpolation $"..."u8 is not supported. You must construct the string first, then convert: Encoding.UTF8.GetBytes($"Hello {name}"). The u8 suffix only works on literal strings.

UTF-8 string literals are used in Doda Browser's HTTP client for zero-allocation request headers. For more C# performance tips, visit DodaTech.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro