Why is this an issue?
Nested ternary operators are hard to read because the mapping between each condition and its result is not immediately obvious, and the order in which the conditions are evaluated is easy to misjudge. Each extra level of nesting increases the effort required to understand which branch produces which value.
public string GetAttendanceStatus(Student student)
{
return student.IsPresent ? "Present" : student.HasExcuse ? "Excused" : "Absent"; // Noncompliant
}
Exceptions
The rule does not flag nested ternary operations inside a lambda expression that is converted to an expression tree
(Expression<TDelegate>), such as the lambdas passed to IQueryable<T> methods (Select,
Where, OrderBy, and similar) when using Entity Framework Core, LINQ to SQL, or another query provider.
None of the usual fixes are available there: a lambda converted to an expression tree cannot have a statement body, so the ternary operation cannot
be rewritten into an if statement (compiler error CS0834). A switch expression is not an option either, because expression
trees cannot contain one at all (compiler error CS8514). Extracting the logic into a separate method compiles, but most query providers cannot
translate a call to a user-defined method, so the query fails at runtime instead. The nested ternary operation is therefore usually the only construct
that both compiles and translates reliably, typically into a SQL CASE WHEN.
IQueryable<string> query = context.Students
.Select(s => s.IsGraduated ? "Graduated" : s.IsEnrolled ? "Enrolled" : "Withdrawn"); // Compliant: expression tree, translated to a SQL CASE WHEN
A switch expression or an extracted method can still be used here, but only after the query has been materialized, for example after
AsEnumerable() or ToList().
How to fix it
Extract the nested ternary operation into a separate statement or expression, so that each condition and its result can be read on their own. Depending on the situation, this can be achieved by:
- extracting the outer condition into an
ifstatement - replacing the chain of conditions with a
switchexpression - extracting the whole expression into a dedicated, well-named method
Code examples
Noncompliant code example
public string GetAttendanceStatus(Student student)
{
return student.IsPresent ? "Present" : student.HasExcuse ? "Excused" : "Absent"; // Noncompliant
}
Compliant solution
public string GetAttendanceStatus(Student student)
{
if (student.IsPresent)
{
return "Present";
}
return student.HasExcuse ? "Excused" : "Absent";
}
A switch expression is a good substitute when all conditions test the same expression:
Noncompliant code example
public string GetGradeLabel(Student student) =>
student.Score >= 90 ? "Excellent" : student.Score >= 70 ? "Good" : "NeedsImprovement"; // Noncompliant
Compliant solution
public string GetGradeLabel(Student student) =>
student.Score switch
{
>= 90 => "Excellent",
>= 70 => "Good",
_ => "Needs improvement",
};
When the nested ternary is just one part of a larger statement, extracting it into a well-named method keeps the surrounding code readable:
Noncompliant code example
public void PrintEnrollmentStatus(Student student)
{
Console.WriteLine($"Status: {(student.IsGraduated ? "Graduated" : student.IsEnrolled ? "Enrolled" : "Withdrawn")}"); // Noncompliant
}
Compliant solution
public void PrintEnrollmentStatus(Student student)
{
Console.WriteLine($"Status: {GetEnrollmentStatus(student)}");
}
private static string GetEnrollmentStatus(Student student)
{
if (student.IsGraduated)
{
return "Graduated";
}
return student.IsEnrolled ? "Enrolled" : "Withdrawn";
}
Resources
Documentation
- Microsoft Learn - switch expression
- Microsoft Learn - Expression tree restrictions
- Microsoft Learn - Client vs. Server Evaluation