C# String Length: Property, Pitfalls, and Performance
c# string length: Understand the C# string Length property, its UTF-16 behavior, null handling, and performance implications for real-world code.
c# string length requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
The Length property on a C# string returns the number of char elements in the string, not the number of visible characters. Each char is a UTF-16 code unit, so the value can differ from what you might expect when the string contains surrogate pairs or combining characters. Understanding this distinction is essential for validation, truncation, and any code that relies on string boundaries.
The Length Property and UTF-16 Code Units
In .NET, a string is an immutable sequence of char values, where each char is a 16-bit UTF-16 code unit. The Length property returns the count of these code units. For most Latin-based text, one code unit equals one character, but that is not guaranteed. For example, the emoji 😀 is represented as two UTF-16 code units (a surrogate pair), so "😀".Length returns 2, not 1.
string emoji = "😀"; Console.WriteLine(emoji.Length); // Output: 2
Similarly, certain accented characters can be represented as a base character plus a combining mark, which also increases the code unit count. If your application needs to count logical characters or grapheme clusters, Length alone is insufficient.
Getting the Length of a Null String
Calling Length on a null string throws a NullReferenceException. This is a common source of runtime errors when strings come from external input or optional parameters. Guard against it with the null-conditional operator or an explicit check.
string? maybeNull = GetStringFromDatabase(); int len = maybeNull?.Length ?? 0; // 0 if null
Alternatively, use string.IsNullOrEmpty when you only care about non-empty strings. But if you need the actual length of a non-null string, the above pattern is direct and safe.
Counting Characters vs. Code Points
To count Unicode code points (which approximate user-perceived characters), you can use the System.Globalization.StringInfo class. It provides a LengthInTextElements property that counts grapheme clusters, handling surrogate pairs and combining sequences correctly.
using System.Globalization; string text = "a😀e\u0301"; // 'a', emoji, 'e' + combining acute accent int codeUnitCount = text.Length; // 5 int textElementCount = new StringInfo(text).LengthInTextElements; // 3
For a simpler approach that counts code points (not full grapheme clusters), you can use LINQ:
int codePointCount = text.EnumerateRunes().Count();
EnumerateRunes is available in .NET Core 3.0+ and gives each Unicode scalar value. This is a good middle ground when you don't need full grapheme clustering.
The following table summarizes the differences:
| Method | Counts | Handles surrogate pairs | Handles combining marks |
|---|---|---|---|
string.Length | UTF-16 code units | No | No |
EnumerateRunes().Count() | Unicode code points | Yes | No (combining marks are separate) |
StringInfo.LengthInTextElements | Grapheme clusters | Yes | Yes |
Performance: Length Is O(1) and Cached
The Length property is stored as a field in the string object, so accessing it is an O(1) operation. There is no iteration or calculation involved. This makes it safe to use repeatedly in loops or comparisons without performance concerns.
However, be careful about creating new strings just to check their length. For example, Trim().Length allocates a new string and then reads its length. If you only need to know whether the trimmed string is empty, use string.IsNullOrWhiteSpace instead, which avoids the allocation.
// Avoid: allocates a trimmed string if (input.Trim().Length == 0) { ... } // Prefer: no allocation if (string.IsNullOrWhiteSpace(input)) { ... }
Similarly, avoid using Length to validate that a string has a minimum number of characters when you actually need to count Unicode characters. The cost of the property itself is trivial, but the logic around it can introduce allocations or incorrect results.
Common Mistakes and Misconceptions
A frequent mistake is using Length to enforce a maximum number of characters in user input. For example, a text field that allows 140 characters per Twitter's old limit should be checked by counting grapheme clusters, not UTF-16 code units. Otherwise, users with emoji or accented characters will be unfairly restricted.
Another misconception is that Length returns the number of bytes. That is only true for ASCII strings. For non-ASCII characters, the byte count depends on the encoding (e.g., UTF-8, UTF-16). Use Encoding.UTF8.GetByteCount if you need byte length.
string text = "café"; int charCount = text.Length; // 4 int byteCount = Encoding.UTF8.GetByteCount(text); // 5
Practical Usage: Validation and Truncation
When you need to truncate a string to a certain number of characters, Length is useful only if you are working with code units. For display purposes, you often want to truncate at a grapheme boundary to avoid splitting a surrogate pair. Here's a simple method that truncates to a maximum number of code points without breaking a surrogate pair:
public static string Truncate(string input, int maxCodePoints) { if (string.IsNullOrEmpty(input) || maxCodePoints <= 0) return string.Empty; var runes = input.EnumerateRunes().Take(maxCodePoints).ToArray(); return new string(runes); }
This uses EnumerateRunes to get Unicode scalar values and then rebuilds the string. It avoids splitting a surrogate pair because each rune is a complete code point. For full grapheme clustering, you would need StringInfo and more complex logic, but for most cases code points are sufficient.
When Length Does Not Reflect Display Width
The Length property also does not account for the visual width of characters. For example, East Asian full-width characters take up more horizontal space than Latin characters, but both count as one code unit. If you are building a UI that aligns text, you cannot rely on Length for width calculations. You would need to use font metrics or a library that measures rendered text.
Similarly, combining characters can change the visual appearance without increasing the code unit count in a way that matches user expectations. For instance, "e\u0301" (e + combining acute accent) has a length of 2 but displays as a single character é. If you are counting visible characters, you need to normalize the string or use grapheme clustering.
Understanding these boundaries helps you choose the right tool: Length for code units, EnumerateRunes for code points, and StringInfo for grapheme clusters. Each has its place, and selecting the correct one prevents subtle bugs in internationalized applications.