Updated on

C# converts a string to a bool with three methods, and all three accept exactly two strings: "true" and "false", in any casing, with leading and trailing white space ignored. "1", "0", "yes" and "" are not boolean text in .NET and none of them converts.

To download the source code for this article, you can visit our GitHub repository.

bool.TryParse() is the one to reach for by default, because it reports failure with a return value instead of an exception. bool.Parse() throws, and Convert.ToBoolean() throws for the same inputs with one exception: given null it returns false.

How Does Convert.ToBoolean() Convert a String to a Bool?

Convert.ToBoolean() turns a string into a bool, and for string input it is bool.Parse() with one extra step in front of it.

The .NET source is short enough to state outright. Convert.ToBoolean(string? value) returns false when value is null, and otherwise hands the string straight to bool.Parse(). That null check is the entire difference between the two methods.

So the strings it accepts are the ones bool.Parse() accepts: "true" and "false", in any casing, with leading or trailing white space ignored. Anything else raises a FormatException.

The overload that also takes an IFormatProvider ignores it. Boolean text is not culture-sensitive in .NET, so passing a CultureInfo changes nothing about which strings convert.

The method has overloads for the numeric types as well, and they follow a different rule. Convert.ToBoolean(int value) returns value != 0. That is why Convert.ToBoolean(1) gives us true while Convert.ToBoolean("1") throws.

The method has a lot of overloads, and this is the documented signature of the one that takes a single string:

public static bool ToBoolean(string? value);

Every string outside the accepted set arrives as a FormatException, so any code that passes text from outside our own program has to handle these exceptions.

So, let’s see how this works with an example:

public static void ToBooleanMethod()
{
    string?[] validString = { null, "true", "True", "    true   ", "false", "False", "    false" };

    string[] invalidString = { "", string.Empty, "t", "    yes   ", "-1", "0", "1" };

    var values = validString.Concat(invalidString);

    foreach (var value in values)
    {
        try
        {
            Console.WriteLine($"Converted '{value}' to {Convert.ToBoolean(value)}.\n");
        }
        catch (FormatException)
        {
            Console.WriteLine($"Unable to convert '{value}' to a Boolean.\n");
        }
    }
}

Here, we concatenate both arrays in a single collection and iterate through each element trying to convert it to bool. So, once we execute this method, it will successfully convert all the strings within the validString array to bool. But it will not convert the strings from the invalidString array.

How Does bool.Parse() Convert a String to a Bool?

bool.Parse() is the method that does the actual work, and the other two route through it or copy its rules.

It compares the string against bool.TrueString and bool.FalseString, two read-only fields whose values are "True" and "False". The comparison is ordinal and case-insensitive, and leading or trailing white space is ignored, so "TRUE", "true" and " True " all give us true.

Nothing else parses. Microsoft’s documentation puts it plainly: we cannot successfully parse numeric strings such as "0" or "1".

Failure arrives as an exception, and which exception depends on the input. A null string raises an ArgumentNullException. Every other unacceptable string raises a FormatException. Catching only FormatException therefore leaves the null case uncovered.

A second overload takes a ReadOnlySpan<char> instead of a string, which is the one to use when the text is already a slice of a larger buffer.

This is the documented signature of the string overload:

public static bool Parse(string value);

Microsoft’s Boolean documentation states the accepted set outright:

Note that only the case-insensitive equivalents of “True” and “False” can be successfully parsed.

Returning false for null while the parse method throws is a deliberate design choice rather than an accident, and .NET makes the same split between int.Parse() and Convert.ToInt32() one type over.

So, let’s see how this works with an example:

public static void ParseMethod()
{
    string[] validString = { "true", "True", "    true   ", "false", "False", "    false" };

    string?[] invalidString = { null, "", string.Empty, "t", "    yes   ", "-1", "0", "1" };

    var values = validString.Concat(invalidString);

    foreach (var value in values)
    {
        try
        {
            Console.WriteLine($"Converted '{value}' to {bool.Parse(value!)}.\n");
        }
        catch (ArgumentNullException)
        {
            Console.WriteLine("Unable to convert null to a Boolean.\n");
        }
        catch (FormatException)
        {
            Console.WriteLine($"Unable to convert '{value}' to a Boolean.\n");
        }
    }
}

The two catch clauses are the point of the example. When we run our application, the output is similar to the one we got from Convert.ToBoolean(), and the only difference is the null element, which lands in the first clause here and converted quietly to false there.

How Do We Convert a String to a Bool Without Exceptions?

bool.TryParse() answers the same question as bool.Parse() and reports failure with a return value instead of an exception.

It takes the string and an out bool, returns true when the string was one of the two accepted words, and false otherwise. The accepted set is identical: case-insensitive "true" and "false", with surrounding white space ignored.

On failure the out parameter is set to false. That is a real value, not a marker, so it cannot tell us whether the string said "false" or was not boolean text at all. The returned flag is the only reliable signal, and ignoring it is the mistake this method exists to prevent.

null is an ordinary failure here rather than an exception. That is the practical reason to prefer this method for anything that arrived from a form, a configuration file, a query string or a database column, where a missing value is expected traffic rather than a bug.

The same pattern exists on every parseable type in .NET, and we cover it in general in our article on Parse and TryParse in C#.

This is the documented signature of the overload we use:

public static bool TryParse(string? value, out bool result);

So, let’s see how this works with an example:

public static void TryParseMethod()
{
    string[] validString = { "true", "True", "    true   ", "false", "False", "    false" };

    string?[] invalidString = { null, "", string.Empty, "t", "    yes   ", "-1", "0", "1" };

    var values = validString.Concat(invalidString);

    foreach (var value in values)
    {
        if (bool.TryParse(value, out bool booleanValue))
        {
            Console.WriteLine($"Conversion successful: '{value}' to {booleanValue}.\n");
        }
        else
        {
            Console.WriteLine($"Conversion Failed: '{value}' to {booleanValue}.\n");
        }
    }
}

As you can see, we are not handling exceptions here as we did with our previous two examples. This means that bool.TryParse is a more suitable method to use if we do not want to handle exceptions when the conversion fails.

Which Strings Convert to a Bool in C#?

Only two strings convert, and all three methods agree on which two.

"true" and "false" convert, in any mixture of upper and lower case, with any amount of leading or trailing white space. bool.TrueString and bool.FalseString define them, and their values are "True" and "False".

Everything else fails. An empty string fails. "1" and "0" fail. "yes", "y" and "t" fail. "on" and "off" fail. There is no switch, no culture and no overload that widens the set.

Only the failure behaviour differs between the three methods, and only for null. Convert.ToBoolean(null) returns false. bool.Parse(null) throws an ArgumentNullException. bool.TryParse(null, out var value) returns false.

So the choice is about what a bad string means to us. Use bool.TryParse() when bad input is ordinary traffic, and either of the other two when a bad string is a bug we want to hear about immediately.

Input stringConvert.ToBoolean(s)bool.Parse(s)bool.TryParse(s, out var b)
"true", "True", "TRUE"truetruereturns true, b is true
"false", "False"falsefalsereturns true, b is false
" true " (surrounding white space)truetruereturns true, b is true
nullfalseArgumentNullExceptionreturns false, b is false
"" and string.EmptyFormatExceptionFormatExceptionreturns false, b is false
"1", "0", "-1"FormatExceptionFormatExceptionreturns false, b is false
"yes", "y", "t"FormatExceptionFormatExceptionreturns false, b is false

How Do We Convert “1”, “0” and “yes” to a Bool in C#?

None of the three built-in methods accepts these, so we write the mapping ourselves.

The tempting shortcut is Convert.ToBoolean(), because Convert.ToBoolean(1) really does return true. The overload taking an int returns value != 0, so 1 is true, 0 is false, and -1 is true as well. The string overload never reaches that code, which is exactly why Convert.ToBoolean("1") throws and Convert.ToBoolean(1) does not.

Routing the string through int.Parse() first would work for digits and still throw on "yes", and it quietly accepts every non-zero number as true.

An explicit mapping is clearer, and it is the one place we get to decide what our own inputs mean. Trim the string, compare without case, list the words we accept, and return null for anything else so the caller can tell a false apart from a failure.

Let’s write that mapping:

public static bool? ToBoolOrNull(string? value) => value?.Trim().ToLowerInvariant() switch
{
    "true" or "yes" or "y" or "1" or "on" => true,
    "false" or "no" or "n" or "0" or "off" => false,
    _ => null
};

The return type is a nullable bool rather than bool, so a caller that gets false knows the input said false and a caller that gets null knows the input was not something we recognise.

The digit route is the one worth naming before we leave it, because converting a string to an int is a solved problem and it is tempting to chain the two conversions instead of writing the mapping out.

Conclusion

.NET accepts two strings as boolean text, "true" and "false", and every one of the three conversion methods stops there. bool.TryParse() is the default because it reports a bad string with a return value, bool.Parse() throws, and Convert.ToBoolean() is bool.Parse() with a null check in front of it. Anything wider, "1" and "yes" included, is a mapping we own and write ourselves.

Tested with .NET 10.0.10.