C# String CompareOrdinal() Method

Beginner
⏱️ 9 min read
📚 Updated: Jul 2026
🎯 5 Examples
String Methods

What You’ll Learn

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.

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.

📝 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

⚡ Quick Reference

StringsCallResult
"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 segmentsCompareOrdinal(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

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\"");
        }
    }
}

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}");
    }
}

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}");
    }
}

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)}");
    }
}

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}");
    }
}

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.

🚀 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.

📝 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).

⚡ 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.

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.

💡 Best Practices

✅ Do

  • 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

Key Takeaways

Knowledge Unlocked

Five things to remember about CompareOrdinal()

Use these points whenever you compare strings ordinally in C#.

5
Core concepts
🔢 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.

Keep Building C# String Skills

Master ordinal comparison, then continue to CompareTo() for comparing strings through an instance method.

Next: CompareTo() →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

6 people found this page helpful