C#idiomatic C#
boolean-logical-operatorscsharp/language-reference/operators

Language

Boolean logical operators - AND, OR, NOT, XOR

C# logical operators perform logical negation (`!`), conjunction (AND - `&`, `&&`), and inclusive and exclusive disjunction (OR - `|`, `||`, `^`) operations with Boolean operands.

  • page csharp/language-reference/operators/boolean-logical-operators
  • updated 01/20/2026

The logical Boolean operators perform logical operations with bool operands. The operators include the unary logical negation (!), binary logical AND (&), OR (|), and exclusive OR (^), and the binary conditional logical AND (&&) and OR (||).

For operands of the integral numeric types, the &, |, and ^ operators perform bitwise logical operations. For more information, see Bitwise and shift operators.


ms.custom: "updateeachrelease"

The C# language reference documents the most recently released version of the C# language. It also contains initial documentation for features in public previews for the upcoming language release.

The documentation identifies any feature first introduced in the last three versions of the language or in current public previews.

Logical negation operator !

The unary prefix ! operator computes the logical negation of its operand. It produces true if the operand evaluates to false, and false if the operand evaluates to true:

sample · csharpdocs/csharp/language-reference/operators/snippets/shared/BooleanLogicalOperators.csNegation

csharp
namespace operators;

public static class BooleanLogicalOperators
{
    public static void Examples()
    {
        Console.WriteLine("==== !, &, |, ^ operators");
        Negation();
        And();
        Or();
        Xor();
        WithNullableBoolean();

        Console.WriteLine("==== && and || operators");
        ConditionalAnd();
        ConditionalOr();

        Console.WriteLine("==== Compound assignment and precedence");
        CompoundAssignment();
        Precedence();
    }

    private static void Negation()
    {
        // <SnippetNegation>
        bool passed = false;
        Console.WriteLine(!passed);  // output: True
        Console.WriteLine(!true);    // output: False
        // </SnippetNegation>
    }

    private static void And()
    {
        // <SnippetAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false & SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // False

        bool b = true & SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetAnd>
    }

    private static void Or()
    {
        // <SnippetOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true | SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // True

        bool b = false | SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetOr>
    }

    private static void Xor()
    {
        // <SnippetXor>
        Console.WriteLine(true ^ true);    // output: False
        Console.WriteLine(true ^ false);   // output: True
        Console.WriteLine(false ^ true);   // output: True
        Console.WriteLine(false ^ false);  // output: False
        // </SnippetXor>
    }

    private static void ConditionalAnd()
    {
        // <SnippetConditionalAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false && SecondOperand();
        Console.WriteLine(a);
        // Output:
        // False

        bool b = true && SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalAnd>
    }

    private static void ConditionalOr()
    {
        // <SnippetConditionalOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true || SecondOperand();
        Console.WriteLine(a);
        // Output:
        // True

        bool b = false || SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalOr>
    }

    private static void WithNullableBoolean()
    {
        // <SnippetWithNullableBoolean>
        bool? test = null;
        Display(!test);         // output: null
        Display(test ^ false);  // output: null
        Display(test ^ null);   // output: null
        Display(true ^ null);   // output: null

        void Display(bool? b) => Console.WriteLine(b is null ? "null" : b.Value.ToString());
        // </SnippetWithNullableBoolean>
    }

    private static void CompoundAssignment()
    {
        // <SnippetCompoundAssignment>
        bool test = true;
        test &= false;
        Console.WriteLine(test);  // output: False

        test |= true;
        Console.WriteLine(test);  // output: True

        test ^= false;
        Console.WriteLine(test);  // output: True
        // </SnippetCompoundAssignment>
    }

    private static void Precedence()
    {
        // <SnippetPrecedence>
        Console.WriteLine(true | true & false);   // output: True
        Console.WriteLine((true | true) & false); // output: False

        bool Operand(string name, bool value)
        {
            Console.WriteLine($"Operand {name} is evaluated.");
            return value;
        }

        var byDefaultPrecedence = Operand("A", true) || Operand("B", true) && Operand("C", false);
        Console.WriteLine(byDefaultPrecedence);
        // Output:
        // Operand A is evaluated.
        // True

        var changedOrder = (Operand("A", true) || Operand("B", true)) && Operand("C", false);
        Console.WriteLine(changedOrder);
        // Output:
        // Operand A is evaluated.
        // Operand C is evaluated.
        // False
        // </SnippetPrecedence>
    }
}

The unary postfix ! operator is the null-forgiving operator.

Logical AND operator &

The & operator computes the logical AND of its operands. The result of x & y is true if both x and y are true. Otherwise, the result is false.

The & operator always evaluates both operands. When the left-hand operand is false, the operation result is false regardless of the value of the right-hand operand. However, the right-hand operand is still evaluated.

In the following example, the right-hand operand of the & operator is a method call, which runs regardless of the value of the left-hand operand:

sample · csharpdocs/csharp/language-reference/operators/snippets/shared/BooleanLogicalOperators.csAnd

csharp
namespace operators;

public static class BooleanLogicalOperators
{
    public static void Examples()
    {
        Console.WriteLine("==== !, &, |, ^ operators");
        Negation();
        And();
        Or();
        Xor();
        WithNullableBoolean();

        Console.WriteLine("==== && and || operators");
        ConditionalAnd();
        ConditionalOr();

        Console.WriteLine("==== Compound assignment and precedence");
        CompoundAssignment();
        Precedence();
    }

    private static void Negation()
    {
        // <SnippetNegation>
        bool passed = false;
        Console.WriteLine(!passed);  // output: True
        Console.WriteLine(!true);    // output: False
        // </SnippetNegation>
    }

    private static void And()
    {
        // <SnippetAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false & SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // False

        bool b = true & SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetAnd>
    }

    private static void Or()
    {
        // <SnippetOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true | SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // True

        bool b = false | SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetOr>
    }

    private static void Xor()
    {
        // <SnippetXor>
        Console.WriteLine(true ^ true);    // output: False
        Console.WriteLine(true ^ false);   // output: True
        Console.WriteLine(false ^ true);   // output: True
        Console.WriteLine(false ^ false);  // output: False
        // </SnippetXor>
    }

    private static void ConditionalAnd()
    {
        // <SnippetConditionalAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false && SecondOperand();
        Console.WriteLine(a);
        // Output:
        // False

        bool b = true && SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalAnd>
    }

    private static void ConditionalOr()
    {
        // <SnippetConditionalOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true || SecondOperand();
        Console.WriteLine(a);
        // Output:
        // True

        bool b = false || SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalOr>
    }

    private static void WithNullableBoolean()
    {
        // <SnippetWithNullableBoolean>
        bool? test = null;
        Display(!test);         // output: null
        Display(test ^ false);  // output: null
        Display(test ^ null);   // output: null
        Display(true ^ null);   // output: null

        void Display(bool? b) => Console.WriteLine(b is null ? "null" : b.Value.ToString());
        // </SnippetWithNullableBoolean>
    }

    private static void CompoundAssignment()
    {
        // <SnippetCompoundAssignment>
        bool test = true;
        test &= false;
        Console.WriteLine(test);  // output: False

        test |= true;
        Console.WriteLine(test);  // output: True

        test ^= false;
        Console.WriteLine(test);  // output: True
        // </SnippetCompoundAssignment>
    }

    private static void Precedence()
    {
        // <SnippetPrecedence>
        Console.WriteLine(true | true & false);   // output: True
        Console.WriteLine((true | true) & false); // output: False

        bool Operand(string name, bool value)
        {
            Console.WriteLine($"Operand {name} is evaluated.");
            return value;
        }

        var byDefaultPrecedence = Operand("A", true) || Operand("B", true) && Operand("C", false);
        Console.WriteLine(byDefaultPrecedence);
        // Output:
        // Operand A is evaluated.
        // True

        var changedOrder = (Operand("A", true) || Operand("B", true)) && Operand("C", false);
        Console.WriteLine(changedOrder);
        // Output:
        // Operand A is evaluated.
        // Operand C is evaluated.
        // False
        // </SnippetPrecedence>
    }
}

The conditional logical AND operator && also computes the logical AND of its operands, but it doesn't evaluate the right-hand operand if the left-hand operand is false.

For operands of the integral numeric types, the & operator computes the bitwise logical AND of its operands. The unary & operator is the address-of operator.

Logical exclusive OR operator ^

The ^ operator computes the logical exclusive OR, also known as the logical XOR, of its operands. The result of x ^ y is true if x is true and y is false, or x is false and y is true. Otherwise, the result is false. For bool operands, the ^ operator computes the same result as the inequality operator !=.

sample · csharpdocs/csharp/language-reference/operators/snippets/shared/BooleanLogicalOperators.csXor

csharp
namespace operators;

public static class BooleanLogicalOperators
{
    public static void Examples()
    {
        Console.WriteLine("==== !, &, |, ^ operators");
        Negation();
        And();
        Or();
        Xor();
        WithNullableBoolean();

        Console.WriteLine("==== && and || operators");
        ConditionalAnd();
        ConditionalOr();

        Console.WriteLine("==== Compound assignment and precedence");
        CompoundAssignment();
        Precedence();
    }

    private static void Negation()
    {
        // <SnippetNegation>
        bool passed = false;
        Console.WriteLine(!passed);  // output: True
        Console.WriteLine(!true);    // output: False
        // </SnippetNegation>
    }

    private static void And()
    {
        // <SnippetAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false & SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // False

        bool b = true & SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetAnd>
    }

    private static void Or()
    {
        // <SnippetOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true | SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // True

        bool b = false | SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetOr>
    }

    private static void Xor()
    {
        // <SnippetXor>
        Console.WriteLine(true ^ true);    // output: False
        Console.WriteLine(true ^ false);   // output: True
        Console.WriteLine(false ^ true);   // output: True
        Console.WriteLine(false ^ false);  // output: False
        // </SnippetXor>
    }

    private static void ConditionalAnd()
    {
        // <SnippetConditionalAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false && SecondOperand();
        Console.WriteLine(a);
        // Output:
        // False

        bool b = true && SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalAnd>
    }

    private static void ConditionalOr()
    {
        // <SnippetConditionalOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true || SecondOperand();
        Console.WriteLine(a);
        // Output:
        // True

        bool b = false || SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalOr>
    }

    private static void WithNullableBoolean()
    {
        // <SnippetWithNullableBoolean>
        bool? test = null;
        Display(!test);         // output: null
        Display(test ^ false);  // output: null
        Display(test ^ null);   // output: null
        Display(true ^ null);   // output: null

        void Display(bool? b) => Console.WriteLine(b is null ? "null" : b.Value.ToString());
        // </SnippetWithNullableBoolean>
    }

    private static void CompoundAssignment()
    {
        // <SnippetCompoundAssignment>
        bool test = true;
        test &= false;
        Console.WriteLine(test);  // output: False

        test |= true;
        Console.WriteLine(test);  // output: True

        test ^= false;
        Console.WriteLine(test);  // output: True
        // </SnippetCompoundAssignment>
    }

    private static void Precedence()
    {
        // <SnippetPrecedence>
        Console.WriteLine(true | true & false);   // output: True
        Console.WriteLine((true | true) & false); // output: False

        bool Operand(string name, bool value)
        {
            Console.WriteLine($"Operand {name} is evaluated.");
            return value;
        }

        var byDefaultPrecedence = Operand("A", true) || Operand("B", true) && Operand("C", false);
        Console.WriteLine(byDefaultPrecedence);
        // Output:
        // Operand A is evaluated.
        // True

        var changedOrder = (Operand("A", true) || Operand("B", true)) && Operand("C", false);
        Console.WriteLine(changedOrder);
        // Output:
        // Operand A is evaluated.
        // Operand C is evaluated.
        // False
        // </SnippetPrecedence>
    }
}

For operands of the integral numeric types, the ^ operator computes the bitwise logical exclusive OR of its operands.

Logical OR operator |

The | operator computes the logical OR of its operands. The result of x | y is true if either x or y evaluates to true. Otherwise, the result is false.

The | operator always evaluates both operands. When the left-hand operand evaluates to true, the operation result is true regardless of the value of the right-hand operand. However, even then, the right-hand operand is evaluated.

In the following example, the right-hand operand of the | operator is a method call, which is performed regardless of the value of the left-hand operand:

sample · csharpdocs/csharp/language-reference/operators/snippets/shared/BooleanLogicalOperators.csOr

csharp
namespace operators;

public static class BooleanLogicalOperators
{
    public static void Examples()
    {
        Console.WriteLine("==== !, &, |, ^ operators");
        Negation();
        And();
        Or();
        Xor();
        WithNullableBoolean();

        Console.WriteLine("==== && and || operators");
        ConditionalAnd();
        ConditionalOr();

        Console.WriteLine("==== Compound assignment and precedence");
        CompoundAssignment();
        Precedence();
    }

    private static void Negation()
    {
        // <SnippetNegation>
        bool passed = false;
        Console.WriteLine(!passed);  // output: True
        Console.WriteLine(!true);    // output: False
        // </SnippetNegation>
    }

    private static void And()
    {
        // <SnippetAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false & SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // False

        bool b = true & SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetAnd>
    }

    private static void Or()
    {
        // <SnippetOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true | SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // True

        bool b = false | SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetOr>
    }

    private static void Xor()
    {
        // <SnippetXor>
        Console.WriteLine(true ^ true);    // output: False
        Console.WriteLine(true ^ false);   // output: True
        Console.WriteLine(false ^ true);   // output: True
        Console.WriteLine(false ^ false);  // output: False
        // </SnippetXor>
    }

    private static void ConditionalAnd()
    {
        // <SnippetConditionalAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false && SecondOperand();
        Console.WriteLine(a);
        // Output:
        // False

        bool b = true && SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalAnd>
    }

    private static void ConditionalOr()
    {
        // <SnippetConditionalOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true || SecondOperand();
        Console.WriteLine(a);
        // Output:
        // True

        bool b = false || SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalOr>
    }

    private static void WithNullableBoolean()
    {
        // <SnippetWithNullableBoolean>
        bool? test = null;
        Display(!test);         // output: null
        Display(test ^ false);  // output: null
        Display(test ^ null);   // output: null
        Display(true ^ null);   // output: null

        void Display(bool? b) => Console.WriteLine(b is null ? "null" : b.Value.ToString());
        // </SnippetWithNullableBoolean>
    }

    private static void CompoundAssignment()
    {
        // <SnippetCompoundAssignment>
        bool test = true;
        test &= false;
        Console.WriteLine(test);  // output: False

        test |= true;
        Console.WriteLine(test);  // output: True

        test ^= false;
        Console.WriteLine(test);  // output: True
        // </SnippetCompoundAssignment>
    }

    private static void Precedence()
    {
        // <SnippetPrecedence>
        Console.WriteLine(true | true & false);   // output: True
        Console.WriteLine((true | true) & false); // output: False

        bool Operand(string name, bool value)
        {
            Console.WriteLine($"Operand {name} is evaluated.");
            return value;
        }

        var byDefaultPrecedence = Operand("A", true) || Operand("B", true) && Operand("C", false);
        Console.WriteLine(byDefaultPrecedence);
        // Output:
        // Operand A is evaluated.
        // True

        var changedOrder = (Operand("A", true) || Operand("B", true)) && Operand("C", false);
        Console.WriteLine(changedOrder);
        // Output:
        // Operand A is evaluated.
        // Operand C is evaluated.
        // False
        // </SnippetPrecedence>
    }
}

The conditional logical OR operator || also computes the logical OR of its operands, but it doesn't evaluate the right-hand operand if the left-hand operand evaluates to true.

For operands of the integral numeric types, the | operator computes the bitwise logical OR of its operands.

Conditional logical AND operator &&

The conditional logical AND operator &&, also known as the "short-circuiting" logical AND operator, computes the logical AND of its operands. The result of x && y is true if both x and y evaluate to true. Otherwise, the result is false. If x evaluates to false, y isn't evaluated.

In the following example, the right-hand operand of the && operator is a method call, which isn't performed if the left-hand operand evaluates to false:

sample · csharpdocs/csharp/language-reference/operators/snippets/shared/BooleanLogicalOperators.csConditionalAnd

csharp
namespace operators;

public static class BooleanLogicalOperators
{
    public static void Examples()
    {
        Console.WriteLine("==== !, &, |, ^ operators");
        Negation();
        And();
        Or();
        Xor();
        WithNullableBoolean();

        Console.WriteLine("==== && and || operators");
        ConditionalAnd();
        ConditionalOr();

        Console.WriteLine("==== Compound assignment and precedence");
        CompoundAssignment();
        Precedence();
    }

    private static void Negation()
    {
        // <SnippetNegation>
        bool passed = false;
        Console.WriteLine(!passed);  // output: True
        Console.WriteLine(!true);    // output: False
        // </SnippetNegation>
    }

    private static void And()
    {
        // <SnippetAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false & SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // False

        bool b = true & SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetAnd>
    }

    private static void Or()
    {
        // <SnippetOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true | SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // True

        bool b = false | SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetOr>
    }

    private static void Xor()
    {
        // <SnippetXor>
        Console.WriteLine(true ^ true);    // output: False
        Console.WriteLine(true ^ false);   // output: True
        Console.WriteLine(false ^ true);   // output: True
        Console.WriteLine(false ^ false);  // output: False
        // </SnippetXor>
    }

    private static void ConditionalAnd()
    {
        // <SnippetConditionalAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false && SecondOperand();
        Console.WriteLine(a);
        // Output:
        // False

        bool b = true && SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalAnd>
    }

    private static void ConditionalOr()
    {
        // <SnippetConditionalOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true || SecondOperand();
        Console.WriteLine(a);
        // Output:
        // True

        bool b = false || SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalOr>
    }

    private static void WithNullableBoolean()
    {
        // <SnippetWithNullableBoolean>
        bool? test = null;
        Display(!test);         // output: null
        Display(test ^ false);  // output: null
        Display(test ^ null);   // output: null
        Display(true ^ null);   // output: null

        void Display(bool? b) => Console.WriteLine(b is null ? "null" : b.Value.ToString());
        // </SnippetWithNullableBoolean>
    }

    private static void CompoundAssignment()
    {
        // <SnippetCompoundAssignment>
        bool test = true;
        test &= false;
        Console.WriteLine(test);  // output: False

        test |= true;
        Console.WriteLine(test);  // output: True

        test ^= false;
        Console.WriteLine(test);  // output: True
        // </SnippetCompoundAssignment>
    }

    private static void Precedence()
    {
        // <SnippetPrecedence>
        Console.WriteLine(true | true & false);   // output: True
        Console.WriteLine((true | true) & false); // output: False

        bool Operand(string name, bool value)
        {
            Console.WriteLine($"Operand {name} is evaluated.");
            return value;
        }

        var byDefaultPrecedence = Operand("A", true) || Operand("B", true) && Operand("C", false);
        Console.WriteLine(byDefaultPrecedence);
        // Output:
        // Operand A is evaluated.
        // True

        var changedOrder = (Operand("A", true) || Operand("B", true)) && Operand("C", false);
        Console.WriteLine(changedOrder);
        // Output:
        // Operand A is evaluated.
        // Operand C is evaluated.
        // False
        // </SnippetPrecedence>
    }
}

The logical AND operator & also computes the logical AND of its operands, but it always evaluates both operands.

Conditional logical OR operator ||

The conditional logical OR operator ||, also known as the "short-circuiting" logical OR operator, computes the logical OR of its operands. The result of x || y is true if either x or y evaluates to true. Otherwise, the result is false. If x evaluates to true, y isn't evaluated.

In the following example, the right-hand operand of the || operator is a method call, which isn't performed if the left-hand operand evaluates to true:

sample · csharpdocs/csharp/language-reference/operators/snippets/shared/BooleanLogicalOperators.csConditionalOr

csharp
namespace operators;

public static class BooleanLogicalOperators
{
    public static void Examples()
    {
        Console.WriteLine("==== !, &, |, ^ operators");
        Negation();
        And();
        Or();
        Xor();
        WithNullableBoolean();

        Console.WriteLine("==== && and || operators");
        ConditionalAnd();
        ConditionalOr();

        Console.WriteLine("==== Compound assignment and precedence");
        CompoundAssignment();
        Precedence();
    }

    private static void Negation()
    {
        // <SnippetNegation>
        bool passed = false;
        Console.WriteLine(!passed);  // output: True
        Console.WriteLine(!true);    // output: False
        // </SnippetNegation>
    }

    private static void And()
    {
        // <SnippetAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false & SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // False

        bool b = true & SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetAnd>
    }

    private static void Or()
    {
        // <SnippetOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true | SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // True

        bool b = false | SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetOr>
    }

    private static void Xor()
    {
        // <SnippetXor>
        Console.WriteLine(true ^ true);    // output: False
        Console.WriteLine(true ^ false);   // output: True
        Console.WriteLine(false ^ true);   // output: True
        Console.WriteLine(false ^ false);  // output: False
        // </SnippetXor>
    }

    private static void ConditionalAnd()
    {
        // <SnippetConditionalAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false && SecondOperand();
        Console.WriteLine(a);
        // Output:
        // False

        bool b = true && SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalAnd>
    }

    private static void ConditionalOr()
    {
        // <SnippetConditionalOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true || SecondOperand();
        Console.WriteLine(a);
        // Output:
        // True

        bool b = false || SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalOr>
    }

    private static void WithNullableBoolean()
    {
        // <SnippetWithNullableBoolean>
        bool? test = null;
        Display(!test);         // output: null
        Display(test ^ false);  // output: null
        Display(test ^ null);   // output: null
        Display(true ^ null);   // output: null

        void Display(bool? b) => Console.WriteLine(b is null ? "null" : b.Value.ToString());
        // </SnippetWithNullableBoolean>
    }

    private static void CompoundAssignment()
    {
        // <SnippetCompoundAssignment>
        bool test = true;
        test &= false;
        Console.WriteLine(test);  // output: False

        test |= true;
        Console.WriteLine(test);  // output: True

        test ^= false;
        Console.WriteLine(test);  // output: True
        // </SnippetCompoundAssignment>
    }

    private static void Precedence()
    {
        // <SnippetPrecedence>
        Console.WriteLine(true | true & false);   // output: True
        Console.WriteLine((true | true) & false); // output: False

        bool Operand(string name, bool value)
        {
            Console.WriteLine($"Operand {name} is evaluated.");
            return value;
        }

        var byDefaultPrecedence = Operand("A", true) || Operand("B", true) && Operand("C", false);
        Console.WriteLine(byDefaultPrecedence);
        // Output:
        // Operand A is evaluated.
        // True

        var changedOrder = (Operand("A", true) || Operand("B", true)) && Operand("C", false);
        Console.WriteLine(changedOrder);
        // Output:
        // Operand A is evaluated.
        // Operand C is evaluated.
        // False
        // </SnippetPrecedence>
    }
}

The logical OR operator | also computes the logical OR of its operands, but always evaluates both operands.

Nullable Boolean logical operators

For bool? operands, the & (logical AND) and | (logical OR) operators support three-valued logic as follows:

  • The & operator returns true only if both its operands evaluate to true. If either x or y evaluates to false, x & y returns false (even if another operand evaluates to null). Otherwise, the result of x & y is null.

  • The | operator produces false only if both its operands evaluate to false. If either x or y evaluates to true, x | y produces true (even if another operand evaluates to null). Otherwise, the result of x | y is null.

The following table presents that semantics:

x y x & y x | y
true true true true
true false false true
true null null true
false true false true
false false false false
false null false null
null true null true
null false false null
null null null null

The behavior of those operators differs from the typical operator behavior with nullable value types. Typically, an operator that is defined for operands of a value type can also be used with operands of the corresponding nullable value type. Such an operator produces null if any of its operands evaluates to null. However, the & and | operators can produce non-null even if one of the operands evaluates to null. For more information about the operator behavior with nullable value types, see the Lifted operators section of the Nullable value types article.

You can also use the ! and ^ operators with bool? operands, as the following example shows:

sample · csharpdocs/csharp/language-reference/operators/snippets/shared/BooleanLogicalOperators.csWithNullableBoolean

csharp
namespace operators;

public static class BooleanLogicalOperators
{
    public static void Examples()
    {
        Console.WriteLine("==== !, &, |, ^ operators");
        Negation();
        And();
        Or();
        Xor();
        WithNullableBoolean();

        Console.WriteLine("==== && and || operators");
        ConditionalAnd();
        ConditionalOr();

        Console.WriteLine("==== Compound assignment and precedence");
        CompoundAssignment();
        Precedence();
    }

    private static void Negation()
    {
        // <SnippetNegation>
        bool passed = false;
        Console.WriteLine(!passed);  // output: True
        Console.WriteLine(!true);    // output: False
        // </SnippetNegation>
    }

    private static void And()
    {
        // <SnippetAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false & SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // False

        bool b = true & SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetAnd>
    }

    private static void Or()
    {
        // <SnippetOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true | SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // True

        bool b = false | SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetOr>
    }

    private static void Xor()
    {
        // <SnippetXor>
        Console.WriteLine(true ^ true);    // output: False
        Console.WriteLine(true ^ false);   // output: True
        Console.WriteLine(false ^ true);   // output: True
        Console.WriteLine(false ^ false);  // output: False
        // </SnippetXor>
    }

    private static void ConditionalAnd()
    {
        // <SnippetConditionalAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false && SecondOperand();
        Console.WriteLine(a);
        // Output:
        // False

        bool b = true && SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalAnd>
    }

    private static void ConditionalOr()
    {
        // <SnippetConditionalOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true || SecondOperand();
        Console.WriteLine(a);
        // Output:
        // True

        bool b = false || SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalOr>
    }

    private static void WithNullableBoolean()
    {
        // <SnippetWithNullableBoolean>
        bool? test = null;
        Display(!test);         // output: null
        Display(test ^ false);  // output: null
        Display(test ^ null);   // output: null
        Display(true ^ null);   // output: null

        void Display(bool? b) => Console.WriteLine(b is null ? "null" : b.Value.ToString());
        // </SnippetWithNullableBoolean>
    }

    private static void CompoundAssignment()
    {
        // <SnippetCompoundAssignment>
        bool test = true;
        test &= false;
        Console.WriteLine(test);  // output: False

        test |= true;
        Console.WriteLine(test);  // output: True

        test ^= false;
        Console.WriteLine(test);  // output: True
        // </SnippetCompoundAssignment>
    }

    private static void Precedence()
    {
        // <SnippetPrecedence>
        Console.WriteLine(true | true & false);   // output: True
        Console.WriteLine((true | true) & false); // output: False

        bool Operand(string name, bool value)
        {
            Console.WriteLine($"Operand {name} is evaluated.");
            return value;
        }

        var byDefaultPrecedence = Operand("A", true) || Operand("B", true) && Operand("C", false);
        Console.WriteLine(byDefaultPrecedence);
        // Output:
        // Operand A is evaluated.
        // True

        var changedOrder = (Operand("A", true) || Operand("B", true)) && Operand("C", false);
        Console.WriteLine(changedOrder);
        // Output:
        // Operand A is evaluated.
        // Operand C is evaluated.
        // False
        // </SnippetPrecedence>
    }
}

The conditional logical operators && and || don't support bool? operands.

Compound assignment

For a binary operator op, a compound assignment expression of the form

csharp
x op= y

Is equivalent to

csharp
x = x op y

Except that x is only evaluated once.

The &, |, and ^ operators support compound assignment, as the following example shows:

sample · csharpdocs/csharp/language-reference/operators/snippets/shared/BooleanLogicalOperators.csCompoundAssignment

csharp
namespace operators;

public static class BooleanLogicalOperators
{
    public static void Examples()
    {
        Console.WriteLine("==== !, &, |, ^ operators");
        Negation();
        And();
        Or();
        Xor();
        WithNullableBoolean();

        Console.WriteLine("==== && and || operators");
        ConditionalAnd();
        ConditionalOr();

        Console.WriteLine("==== Compound assignment and precedence");
        CompoundAssignment();
        Precedence();
    }

    private static void Negation()
    {
        // <SnippetNegation>
        bool passed = false;
        Console.WriteLine(!passed);  // output: True
        Console.WriteLine(!true);    // output: False
        // </SnippetNegation>
    }

    private static void And()
    {
        // <SnippetAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false & SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // False

        bool b = true & SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetAnd>
    }

    private static void Or()
    {
        // <SnippetOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true | SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // True

        bool b = false | SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetOr>
    }

    private static void Xor()
    {
        // <SnippetXor>
        Console.WriteLine(true ^ true);    // output: False
        Console.WriteLine(true ^ false);   // output: True
        Console.WriteLine(false ^ true);   // output: True
        Console.WriteLine(false ^ false);  // output: False
        // </SnippetXor>
    }

    private static void ConditionalAnd()
    {
        // <SnippetConditionalAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false && SecondOperand();
        Console.WriteLine(a);
        // Output:
        // False

        bool b = true && SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalAnd>
    }

    private static void ConditionalOr()
    {
        // <SnippetConditionalOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true || SecondOperand();
        Console.WriteLine(a);
        // Output:
        // True

        bool b = false || SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalOr>
    }

    private static void WithNullableBoolean()
    {
        // <SnippetWithNullableBoolean>
        bool? test = null;
        Display(!test);         // output: null
        Display(test ^ false);  // output: null
        Display(test ^ null);   // output: null
        Display(true ^ null);   // output: null

        void Display(bool? b) => Console.WriteLine(b is null ? "null" : b.Value.ToString());
        // </SnippetWithNullableBoolean>
    }

    private static void CompoundAssignment()
    {
        // <SnippetCompoundAssignment>
        bool test = true;
        test &= false;
        Console.WriteLine(test);  // output: False

        test |= true;
        Console.WriteLine(test);  // output: True

        test ^= false;
        Console.WriteLine(test);  // output: True
        // </SnippetCompoundAssignment>
    }

    private static void Precedence()
    {
        // <SnippetPrecedence>
        Console.WriteLine(true | true & false);   // output: True
        Console.WriteLine((true | true) & false); // output: False

        bool Operand(string name, bool value)
        {
            Console.WriteLine($"Operand {name} is evaluated.");
            return value;
        }

        var byDefaultPrecedence = Operand("A", true) || Operand("B", true) && Operand("C", false);
        Console.WriteLine(byDefaultPrecedence);
        // Output:
        // Operand A is evaluated.
        // True

        var changedOrder = (Operand("A", true) || Operand("B", true)) && Operand("C", false);
        Console.WriteLine(changedOrder);
        // Output:
        // Operand A is evaluated.
        // Operand C is evaluated.
        // False
        // </SnippetPrecedence>
    }
}

Operator precedence

The following list orders logical operators in groups starting from the highest precedence to the lowest:

Use parentheses, (), to change the order of evaluation imposed by operator precedence:

sample · csharpdocs/csharp/language-reference/operators/snippets/shared/BooleanLogicalOperators.csPrecedence

csharp
namespace operators;

public static class BooleanLogicalOperators
{
    public static void Examples()
    {
        Console.WriteLine("==== !, &, |, ^ operators");
        Negation();
        And();
        Or();
        Xor();
        WithNullableBoolean();

        Console.WriteLine("==== && and || operators");
        ConditionalAnd();
        ConditionalOr();

        Console.WriteLine("==== Compound assignment and precedence");
        CompoundAssignment();
        Precedence();
    }

    private static void Negation()
    {
        // <SnippetNegation>
        bool passed = false;
        Console.WriteLine(!passed);  // output: True
        Console.WriteLine(!true);    // output: False
        // </SnippetNegation>
    }

    private static void And()
    {
        // <SnippetAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false & SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // False

        bool b = true & SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetAnd>
    }

    private static void Or()
    {
        // <SnippetOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true | SecondOperand();
        Console.WriteLine(a);
        // Output:
        // Second operand is evaluated.
        // True

        bool b = false | SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetOr>
    }

    private static void Xor()
    {
        // <SnippetXor>
        Console.WriteLine(true ^ true);    // output: False
        Console.WriteLine(true ^ false);   // output: True
        Console.WriteLine(false ^ true);   // output: True
        Console.WriteLine(false ^ false);  // output: False
        // </SnippetXor>
    }

    private static void ConditionalAnd()
    {
        // <SnippetConditionalAnd>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = false && SecondOperand();
        Console.WriteLine(a);
        // Output:
        // False

        bool b = true && SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalAnd>
    }

    private static void ConditionalOr()
    {
        // <SnippetConditionalOr>
        bool SecondOperand()
        {
            Console.WriteLine("Second operand is evaluated.");
            return true;
        }

        bool a = true || SecondOperand();
        Console.WriteLine(a);
        // Output:
        // True

        bool b = false || SecondOperand();
        Console.WriteLine(b);
        // Output:
        // Second operand is evaluated.
        // True
        // </SnippetConditionalOr>
    }

    private static void WithNullableBoolean()
    {
        // <SnippetWithNullableBoolean>
        bool? test = null;
        Display(!test);         // output: null
        Display(test ^ false);  // output: null
        Display(test ^ null);   // output: null
        Display(true ^ null);   // output: null

        void Display(bool? b) => Console.WriteLine(b is null ? "null" : b.Value.ToString());
        // </SnippetWithNullableBoolean>
    }

    private static void CompoundAssignment()
    {
        // <SnippetCompoundAssignment>
        bool test = true;
        test &= false;
        Console.WriteLine(test);  // output: False

        test |= true;
        Console.WriteLine(test);  // output: True

        test ^= false;
        Console.WriteLine(test);  // output: True
        // </SnippetCompoundAssignment>
    }

    private static void Precedence()
    {
        // <SnippetPrecedence>
        Console.WriteLine(true | true & false);   // output: True
        Console.WriteLine((true | true) & false); // output: False

        bool Operand(string name, bool value)
        {
            Console.WriteLine($"Operand {name} is evaluated.");
            return value;
        }

        var byDefaultPrecedence = Operand("A", true) || Operand("B", true) && Operand("C", false);
        Console.WriteLine(byDefaultPrecedence);
        // Output:
        // Operand A is evaluated.
        // True

        var changedOrder = (Operand("A", true) || Operand("B", true)) && Operand("C", false);
        Console.WriteLine(changedOrder);
        // Output:
        // Operand A is evaluated.
        // Operand C is evaluated.
        // False
        // </SnippetPrecedence>
    }
}

For the complete list of C# operators ordered by precedence level, see the Operator precedence section of the C# operators article.

Operator overloadability

A user-defined type can overload the !, &, |, and ^ operators. When a binary operator is overloaded, the corresponding compound assignment operator is also implicitly overloaded. Beginning with C# 14, a user-defined type can explicitly overload the compound assignment operators to provide a more efficient implementation. Typically, a type overloads these operators because the value can be updated in place, rather than allocating a new instance to hold the result of the binary operation. If a type doesn't provide an explicit overload, the compiler generates the implicit overload.

A user-defined type can't overload the conditional logical operators && and ||. However, if a user-defined type overloads the true and false operators and the & or | operator in a certain way, the && or || operation, respectively, can be evaluated for the operands of that type. For more information, see the User-defined conditional logical operators section of the C# language specification.

C# language specification

For more information, see the following sections of the C# language specification:

See also