The static String.CompareOrdinal() method compares two strings using ordinal rules—it walks UTF-16 code units in order without culture or locale influence. It returns an int ideal for sorting file paths, dictionary keys, and protocol identifiers where predictable, fast comparison matters.
01
Ordinal Compare
Raw code unit order.
02
Static Method
Call on String class.
03
int Return
< 0, 0, or > 0.
04
Case-Sensitive
A ≠ a by default.
05
Partial Compare
Index + length overload.
06
vs Compare()
Culture vs ordinal.
Fundamentals
Definition and Usage
In C#, String.CompareOrdinal(string strA, string strB) performs a binary-style ordinal comparison. The runtime compares each UTF-16 code unit in strA against the corresponding code unit in strB from left to right until a difference appears or one string ends.
Unlike culture-aware Compare(), ordinal comparison ignores linguistic rules (such as how a specific language sorts accented letters). That makes it predictable and fast—perfect for internal identifiers, HTTP headers, file paths on case-sensitive systems, and hash-table keys where you need the same result on every machine.
💡
Beginner Tip
CompareOrdinal(a, b) is equivalent to string.Compare(a, b, StringComparison.Ordinal). There is no built-in CompareOrdinalIgnoreCase method—use StringComparison.OrdinalIgnoreCase when you need case-insensitive ordinal comparison.
Foundation
📝 Syntax
Two overloads declared on System.String:
C#
public static int CompareOrdinal(string strA, string strB);
public static int CompareOrdinal(
string strA, int indexA,
string strB, int indexB,
int length);
Parameters
strA, strB — the strings to compare (either may be null).
indexA, indexB — starting positions for the partial overload.
length — number of characters to compare in each string from the start index.
Return Value
< 0 → strA is less than strB
0 → strA equals strB (ordinal rules)
> 0 → strA is greater than strB
Cheat Sheet
⚡ Quick Reference
Strings
Call
Result
"apple", "banana"
CompareOrdinal(a, b)
< 0
"test", "test"
CompareOrdinal(a, b)
0
"Hello", "hello"
CompareOrdinal(a, b)
< 0 (H before h)
"file.txt", "file.log"
CompareOrdinal(a, b)
> 0 ('t' after '.' > 'l')
Partial segments
CompareOrdinal(a, 0, b, 0, 4)
Compare first 4 chars
Full
string.CompareOrdinal(a, b)
Entire strings
Equal?
CompareOrdinal(a, b) == 0
Ordinal equality
Partial
CompareOrdinal(a, i, b, j, len)
Substring compare
Equivalent
Compare(a, b, StringComparison.Ordinal)
Same semantics
Hands-On
Examples Gallery
Run with dotnet run. Each example demonstrates ordinal comparison from basic ordering to case sensitivity, equivalence with StringComparison.Ordinal, and partial segment comparison.
📚 Getting Started
Compare two strings ordinally and read the integer result.
Example 1 — Basic CompareOrdinal() Usage
Compare "apple" and "banana". Because 'a' < 'b' in Unicode code unit order, the result is negative.
C#
using System;
class Program {
static void Main() {
string str1 = "apple";
string str2 = "banana";
int result = string.CompareOrdinal(str1, str2);
Console.WriteLine($"Comparison result: {result}");
if (result < 0) {
Console.WriteLine("\"apple\" comes before \"banana\"");
}
}
}
📤 Output:
Comparison result: -1
"apple" comes before "banana"
How It Works
Ordinal comparison compares code units directly. The exact negative value (often -1) is an implementation detail—what matters is the sign indicating str1 sorts before str2.
Example 2 — Ordinally Equal Strings
When every code unit matches and lengths are equal, CompareOrdinal() returns 0.
C#
using System;
class Program {
static void Main() {
string a = "C#";
string b = "C#";
int result = string.CompareOrdinal(a, b);
Console.WriteLine($"Result: {result}");
Console.WriteLine($"Ordinally equal: {result == 0}");
}
}
📤 Output:
Result: 0
Ordinally equal: True
How It Works
A result of 0 means the strings are ordinally identical. This is stricter than “looks the same to a user”—culture-aware Compare() might treat some Unicode sequences differently in edge cases.
📈 Practical Patterns
Case rules, equivalence, and partial segments.
Example 3 — Case-Sensitive Ordinal Comparison
Ordinal comparison treats uppercase and lowercase as different code units—important for case-sensitive file systems and keys.
C#
using System;
class Program {
static void Main() {
string upper = "Report.PDF";
string lower = "report.pdf";
int ordinal = string.CompareOrdinal(upper, lower);
Console.WriteLine($"CompareOrdinal: {ordinal}");
int ignoreCase = string.Compare(
upper, lower, StringComparison.OrdinalIgnoreCase);
Console.WriteLine($"OrdinalIgnoreCase: {ignoreCase}");
}
}
📤 Output:
CompareOrdinal: -1
OrdinalIgnoreCase: 0
How It Works
'R' (code unit 82) comes before 'r' (114), so the ordinally case-sensitive result is non-zero. For case-insensitive ordinal matching, use StringComparison.OrdinalIgnoreCase instead of CompareOrdinal().
Example 4 — CompareOrdinal() vs StringComparison.Ordinal
Verify that both APIs produce the same result—choose whichever reads clearer in your code.
C#
using System;
class Program {
static void Main() {
string path1 = "apple";
string path2 = "banana";
int viaCompareOrdinal = string.CompareOrdinal(path1, path2);
int viaStringComparison = string.Compare(
path1, path2, StringComparison.Ordinal);
Console.WriteLine($"CompareOrdinal: {viaCompareOrdinal}");
Console.WriteLine($"StringComparison: {viaStringComparison}");
Console.WriteLine($"Same sign: {Math.Sign(viaCompareOrdinal) == Math.Sign(viaStringComparison)}");
}
}
📤 Output:
CompareOrdinal: -1
StringComparison: -1
Same sign: True
How It Works
Both calls use ordinal rules. CompareOrdinal() is a dedicated shortcut; StringComparison.Ordinal fits when you already use the Compare() overload family consistently.
Example 5 — Partial Ordinal Comparison
Compare only a segment of each string using the index and length overload—useful for prefix checks without allocating substrings.
C#
using System;
class Program {
static void Main() {
string header1 = "GET /api/users HTTP/1.1";
string header2 = "GET /api/orders HTTP/1.1";
// Compare "GET " (4 chars) — should be equal
int method = string.CompareOrdinal(
header1, 0, header2, 0, 4);
// Compare "/api/" prefix (5 chars starting at index 4)
int route = string.CompareOrdinal(
header1, 4, header2, 4, 5);
Console.WriteLine($"Method line prefix: {method}");
Console.WriteLine($"/api/ prefix: {route}");
}
}
📤 Output:
Method line prefix: 0
/api/ prefix: 0
How It Works
The partial overload compares exactly length characters starting at each index. Both headers share "GET " and "/api/" at the same positions, so those segments return 0 even though the full strings differ later.
Applications
🚀 Common Use Cases
File and URL paths — predictable ordering on case-sensitive systems.
Dictionary and hash keys — fast, culture-independent key comparison.
HTTP headers and protocol tokens — exact code-unit matching without locale rules.
Version strings — ordinal compare works well for fixed-format identifiers (with caution for semantic versioning).
Prefix checks — partial overload to test leading segments without Substring().
🧠 How CompareOrdinal() Works
1
You pass two strings
Optionally specify start indexes and a length for partial comparison.
Input
2
Code units are compared
Each UTF-16 char is compared numerically left to right—no culture rules applied.
Ordinal
3
First difference decides
If all compared units match and lengths match, return 0. Otherwise return a signed int reflecting order.
Result
=
📊
int ordering returned
Use for sorting, equality (== 0), or branching on less-than / greater-than.
Important
📝 Notes
CompareOrdinal() is case-sensitive—"A" and "a" are not equal.
It compares UTF-16 code units, not user-perceived graphemes—surrogate pairs (emoji) use two code units.
Equivalent to string.Compare(a, b, StringComparison.Ordinal).
For case-insensitive ordinal, use StringComparison.OrdinalIgnoreCase—there is no CompareOrdinalIgnoreCase static method.
Use culture-aware Compare() for names and words shown to users in sorted lists.
null is less than any non-null string; two null values compare as equal (0).
Performance
⚡ Optimization
Ordinal comparison skips culture lookup and collation tables, making it faster than culture-sensitive Compare() for most inputs. The partial overload avoids allocating temporary substrings when you only need to test a prefix or segment. For high-throughput scenarios (hash tables, sorting millions of internal keys), prefer ordinal rules unless you explicitly need locale-aware ordering.
Wrap Up
Conclusion
The C# CompareOrdinal() method is the go-to tool for fast, culture-independent string ordering. It compares UTF-16 code units directly and returns a signed integer you can use for sorting, equality checks, and prefix validation.
Practice the examples until ordinal vs culture-aware comparison is clear, then continue to CompareTo() for instance-style string ordering.
Use CompareOrdinal() for paths, keys, and protocol strings
Check == 0 for ordinal equality
Use the partial overload for prefix tests without Substring()
Pick OrdinalIgnoreCase when case should not matter
Prefer StringComparer.Ordinal when sorting collections
❌ Don’t
Use ordinal compare for culturally sorted display names
Assume CompareOrdinal ignores case (it does not)
Confuse ordinal with raw UTF-8 byte comparison
Treat the int result as a boolean for equality
Sort user-facing word lists without considering culture
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about CompareOrdinal()
Use these points whenever you compare strings ordinally in C#.
5
Core concepts
📊01
Ordinal Rules
No culture influence.
Basics
🔢02
int Return
< 0, 0, or > 0.
Return
🔒03
Case-Sensitive
A ≠ a by default.
Rule
✅04
= Ordinal
Same as StringComparison.Ordinal.
API
✂05
Partial Overload
Compare a segment.
Pattern
❓ Frequently Asked Questions
CompareOrdinal() compares two strings using ordinal (binary) rules—it walks UTF-16 code units left to right without culture-specific sorting rules. It returns int: negative if strA comes first, zero if equal, positive if strA comes after strB.
string.CompareOrdinal(strA, strB) for full strings. Partial compare: string.CompareOrdinal(strA, indexA, strB, indexB, length). Both are static methods on the String class.
It returns int—not bool. Less than 0 means strA is less than strB, 0 means they are equal under ordinal rules, greater than 0 means strA is greater. Check == 0 for equality.
Yes. Uppercase and lowercase letters have different code unit values, so "Hello" and "hello" do not compare as equal. For case-insensitive ordinal comparison, use string.Compare(a, b, StringComparison.OrdinalIgnoreCase).
CompareOrdinal() ignores culture and locale—it compares raw Unicode code units in order. Compare() uses culture-aware rules by default, so sort order can vary by language. Use CompareOrdinal() for paths, keys, and protocol strings; use Compare() for user-visible sorted lists.
Yes. string.CompareOrdinal(a, b) is equivalent to string.Compare(a, b, StringComparison.Ordinal). CompareOrdinal() is a dedicated, fast API for the same ordinal comparison semantics.
Did you know?
StringComparer.Ordinal and StringComparer.OrdinalIgnoreCase wrap the same comparison rules as CompareOrdinal() and StringComparison.OrdinalIgnoreCase. When sorting List<string> or using Dictionary<string, T>, passing an ordinal comparer ensures consistent, culture-independent behavior.