How to Check if a String is a Number in C#

Mastering Robust Input Validation and Conversion in .NET

Validating user input is a cornerstone of building robust, reliable applications. One common scenario is checking whether a string represents a numeric value – a frequent requirement in data entry, parsing, financial calculations, or configuration processing.

C# provides several ways to perform this check, each with subtle differences in performance, culture awareness, precision, and error handling.

This guide explores all modern approaches, including best practices and advanced scenarios.


πŸ” The Problem: Ambiguity in Numeric Parsing

Consider the following challenges developers face:

  • "123" is clearly numeric, but what about "123.45"?
  • How should "1,000" or "0xFF" be interpreted?
  • Should whitespace, signs (+, -), or exponential notation (1.23e4) be allowed?
  • What’s the difference between int.TryParse, double.TryParse, decimal.TryParse, and float.TryParse?
  • How can we validate numeric input without throwing exceptions or losing performance?

Using Convert.ToInt32 or int.Parse blindly can lead to runtime exceptions, slowing applications or causing crashes. Modern C# provides safer, more robust patterns for validation.


⚑ The Solution: Use the Appropriate Parsing and Validation Method

C# provides multiple ways to determine whether a string is numeric:

  1. TryParse methods – robust and exception-free
  2. Regex matching – flexible pattern-based validation
  3. LINQ / custom parsing – specialized scenarios

1️⃣ Using TryParse Methods

Definition

The TryParse methods attempt to parse a string into a numeric type without throwing exceptions. They return true if successful, false otherwise.

Example: Checking for Integers

string input = "123";
bool isNumeric = int.TryParse(input, out int result);

Console.WriteLine(isNumeric); // True
Console.WriteLine(result);    // 123

Key Points

  • Works for int, long, float, double, decimal, byte, etc.
  • Prevents exceptions on invalid input
  • Allows culture-specific parsing with overloads:
bool isDouble = double.TryParse(
    "123.45",
    NumberStyles.Float,
    CultureInfo.InvariantCulture,
    out double value
);
  • Handles signed numbers, decimals, and exponential notation with proper NumberStyles.

Example: Handling Different Number Types

string[] inputs = { "42", "3.1415", "-100", "1e5", "abc" };

foreach (var s in inputs)
{
    if (int.TryParse(s, out _))
        Console.WriteLine($"{s} is an integer.");
    else if (double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out _))
        Console.WriteLine($"{s} is a floating-point number.");
    else
        Console.WriteLine($"{s} is not numeric.");
}

Output:

42 is an integer.
3.1415 is a floating-point number.
-100 is an integer.
1e5 is a floating-point number.
abc is not numeric.

2️⃣ Using Regular Expressions

Sometimes numeric validation must follow custom formats, e.g., optional signs, thousands separators, or scientific notation.

Example: Basic Numeric Regex

using System.Text.RegularExpressions;

string pattern = @"^[+-]?\d+(\.\d+)?$";
string input = "-123.45";

bool isNumeric = Regex.IsMatch(input, pattern);
Console.WriteLine(isNumeric); // True

Advanced Patterns

  • Include exponential notation:
string scientificPattern = @"^[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$";
  • Validate thousands separators for en-US style:
string thousandsPattern = @"^\d{1,3}(,\d{3})*(\.\d+)?$";

Regex pros: Flexible for custom numeric formats.
Regex cons: More expensive than TryParse for large datasets; complex patterns can be hard to maintain.


3️⃣ Custom Parsing Approaches

For advanced scenarios, you can combine LINQ, Span<char>, and culture-aware parsing:

string input = "12345";

bool isNumeric = input.AsSpan().All(c => char.IsDigit(c));
Console.WriteLine(isNumeric); // True

Pros: Fast, minimal allocations, no exceptions.
Cons: Only works for integers without signs or decimals.


πŸ”¬ Under the Hood: TryParse vs Parse

FeatureParseTryParse
ExceptionsThrows if invalidReturns false if invalid
PerformanceSlower due to exception handlingFaster, exception-free
Use caseTrusted inputUser input, untrusted sources

Tip: Always use TryParse for user input or external data, especially in high-performance applications.


🧱 Advanced Scenarios

1. Culture-Specific Parsing

string number = "1,234.56";
bool success = double.TryParse(number, NumberStyles.Number, new CultureInfo("en-US"), out double value);
Console.WriteLine(success); // True

2. Nullable Numeric Checks

int? ParseNullableInt(string s)
{
    return int.TryParse(s, out int result) ? result : null;
}

Console.WriteLine(ParseNullableInt("42"));   // 42
Console.WriteLine(ParseNullableInt("abc"));  // null

3. Numeric Validation in Collections

string[] inputs = { "10", "abc", "3.14" };
var numericValues = inputs
    .Where(s => double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out _))
    .ToList();

Console.WriteLine(string.Join(", ", numericValues)); // 10, 3.14

🧰 Best Practices

βœ… Use TryParse whenever input is untrusted.
βœ… Specify NumberStyles and CultureInfo for reliable parsing across locales.
βœ… Use Regex only for custom numeric formats.
βœ… Avoid Parse unless input is guaranteed to be valid.
βœ… For performance-critical code, consider Span<char> or ReadOnlySpan<char> checks to avoid allocations.
βœ… Always handle nullable numeric conversion to prevent runtime exceptions.


Summary

ApproachProsConsUse Case
TryParseFast, exception-free, built-inRequires type-specific callMost robust for numeric validation
ParseSimple, built-inThrows on invalid inputOnly trusted input
RegexFlexible, pattern-basedSlower, complex patternsCustom numeric formats, validation rules
Span / LINQHigh-performance, allocation-freeLimited to simple formatsLarge-scale or high-speed numeric checks

Final Thoughts

Determining whether a string represents a numeric value is a fundamental skill in C#:

  • Impacts input validation, data parsing, and calculation correctness.
  • Affects performance, safety, and maintainability.
  • Modern C# provides multiple tools: TryParse, Regex, and advanced span-based checks.

For robust, production-ready applications, TryParse with culture-aware options is the safest default. Regex and custom parsing should be reserved for specialised numeric formats or validation rules.

Mastering these techniques ensures your applications handle numeric input correctly, efficiently, and securely.