Menu

C# Ternary Operator (?:): Syntax, Types, Nesting and ??

The C# conditional operator condition ? a : b picks one of two values. How it evaluates, why both branches need a common type (CS0173) and the cast that fixes it, nested ternaries, parentheses in string interpolation, and when ?? and ?. say it better.

This page includes runnable editors - edit, run, and see output instantly.

The conditional operator, usually called the ternary operator, chooses between two values in a single expression: condition ? valueIfTrue : valueIfFalse.

Output:

0 items, shipping 4.99
1 item, shipping 4.99
5 items, shipping 0

The condition must be a bool. After it is evaluated, only one of the two branches runs; the other is never evaluated. That makes the operator safe for guarded access such as list.Count > 0 ? list[0] : "empty", where evaluating list[0] on an empty list would throw.

Ternary Versus if/else

The ternary is an expression: it produces a value that you assign, pass or return. An if statement runs statements. These two methods do the same thing:

// with if/else
static string Status(int stock)
{
    if (stock > 0)
        return "in stock";
    else
        return "sold out";
}

// with the ternary
static string Status(int stock) => stock > 0 ? "in stock" : "sold out";

Use the ternary when both branches are short values of the same kind. Use if when a branch runs several statements, has side effects, or when the condition is long enough that the whole line no longer fits comfortably.

The ternary cannot replace an if that only performs actions. This does not compile:

stock > 0 ? Ship(order) : Refund(order);
// error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement

There is also no ternary without an else: both ? and : are always required, because the expression must have a value in both cases.

Both Branches Need a Common Type

The compiler works out the type of the whole expression from its two branches. One branch must convert implicitly to the other's type. When neither does, you get CS0173:

var discount = isMember ? 10 : null;
// error CS0173: Type of conditional expression cannot be determined because
// there is no implicit conversion between 'int' and '<null>'

var label = inStock ? 1 : "none";
// error CS0173: ... between 'int' and 'string'

The fix is to cast one branch to the type you want, so the other converts to it:

Output:

no discount
7
3.5

points / 2.0 : 0 needs no cast: 0 is an int, which converts implicitly to double, so the expression is a double.

C# 9 added target typing: when the expression is assigned to a declared type, the compiler uses that type. int? discount = isMember ? 10 : null; compiles in C# 9 and later. With var there is no target type, so var discount = isMember ? 10 : null; still fails in every version.

Precedence and Parentheses

The conditional operator has very low precedence, lower than +, == and &&. That is convenient in a > b ? a : b, and surprising inside string concatenation:

Console.WriteLine("Status: " + isActive ? "on" : "off");
// error CS0029: Cannot implicitly convert type 'string' to 'bool'

The compiler reads the condition as "Status: " + isActive, a string. Parentheses around the ternary fix it: "Status: " + (isActive ? "on" : "off").

String interpolation has its own trap. Inside { }, a colon starts a format specifier ({price:F2}), so a bare ternary confuses the parser. Wrap it in parentheses:

Output:

2 users online
You have 1 unread message
Status: online

Nested Ternaries

The operator is right-associative, so a ? x : b ? y : z groups as a ? x : (b ? y : z). A small chain laid out one condition per line is readable:

Output:

512 B
20 KB
5 MB

Past two or three levels, or when conditions test different things, switch to if/else if or a switch expression. Nesting inside the true branch (a ? (b ? x : y) : z) is the version that becomes hard to follow first.

?? and ?. Replace Common Ternaries

Many ternaries exist only to handle null. C# has shorter operators for those:

TernaryShorter formMeaning
name != null ? name : "guest"name ?? "guest"fallback when null
customer != null ? customer.Email : nullcustomer?.Emailmember access that tolerates null
c != null && c.Address != null ? c.Address.City : "unknown"c?.Address?.City ?? "unknown"both combined
value != null ? value : throw new ArgumentNullException(...)value ?? throw new ArgumentNullException(...)fail fast

Output:

Lena from Berlin
guest from unknown
guest from unknown

A throw expression is also allowed as either branch of a ternary: int age = input >= 0 ? input : throw new ArgumentOutOfRangeException(nameof(input));.

The ref Conditional

Since C# 7.2, a ternary can choose between two variables rather than two values, and you can assign through the result:

// C# 7.2 and later
int wins = 0, losses = 0;
bool won = true;

ref int counter = ref (won ? ref wins : ref losses);
counter++;               // increments wins

Both branches must be ref to variables of the same type. It is rare in application code; it exists mainly for performance-sensitive code that works with large structs or arrays without copying them.

Frequently Asked Questions

What is the ternary operator in C#?

It is the conditional operator condition ? valueIfTrue : valueIfFalse, the only C# operator with three operands. It evaluates the condition, then evaluates and returns exactly one of the two values: string label = age >= 18 ? "adult" : "minor";.

Can I use a ternary without an else in C#?

No. Both the ? and the : parts are required, because the expression must always produce a value. If you only want to do something when a condition holds, use an if statement. The ternary also cannot stand alone as a statement: x > 0 ? A() : B(); is error CS0201.

Why do I get "Type of conditional expression cannot be determined"?

The two branches have no common type, for example var x = found ? 42 : null; (int and null) or found ? 1 : "none". Cast one branch so a type exists: found ? (int?)42 : null. Since C# 9, a declared target type also works: int? x = found ? 42 : null; compiles, but var still fails.

How do I use the ternary operator inside string interpolation?

Wrap it in parentheses: $"{(count == 1 ? "item" : "items")}". Without them, the : is read as the start of a format specifier and the code does not compile.

Can you nest ternary operators in C#?

Yes. The operator is right-associative, so a ? x : b ? y : z means a ? x : (b ? y : z). One level of nesting laid out on separate lines reads fine; deeper chains are clearer as an if/else if chain or a switch expression.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED