Refactoring Traditional Statements into Expressions in C#
When programming in C#, many developers use traditional statements like if-statements, switch-statements, for-loops, and foreach-loops. While these are powerful tools, expressions and other features in recent C# versions offers more concise and readable alternatives. In this article, I'll share a few tips on how you can refactor these traditional statements into sleeker expressions.
Replacing if-statements and switch-statements with Expressions
Traditional if-statements are useful but can sometimes lead to verbose code, especially for simple evaluations. By transitioning to expression-bodied members or conditional operators, we can often reduce the lines of code and enhance readability.
Using Conditional Operator
Instead of a traditional if-else statement, the conditional (ternary) operator can be used.
The conditional ternary operator in C# is a concise way to evaluate one of two expressions based on a boolean condition. It's a shorthand for the if-else
statement and is denoted by the ?
and :
symbols.
Example:
int value = 10;
string result = (value > 5) ? "Greater than 5" : "5 or less";
In the above example, since the condition value > 5
is true, the result
will be set to "Greater than 5". If the value was 5 or less, the result
would be set to "5 or less".
Refactoring
Let's use a bit more complex example where I first write the traditional if-statement, directly followed by a refactored example using conditional operator expression.
var result =" ";
if(isValid){
if(theValue < 0){
result = "Negative";
}else if(theValue < 500){
result = "Small Positive";
}else{
result = "High Positive";
}
}else{
result = "Not Valid";
}
// Can be refactored to more condensed code
var result = isValid ?
theValue < 0 ?
"Negative" : theValue < 500 ?
"Small Positive" : "HighPositive" :
"Not Valid";
Using Null Coalescing operator
The null coalescing expression in C# allows you to provide a default value for nullable value types or reference types. It returns the left-hand operand if it's not null; otherwise, it returns the right-hand operand. The ??
operator is used to represent this expression.
Example
string name = null;
string displayName = name ?? "Guest";
In this example, since name
is null
, the displayName
will be set to "Guest"
. If name
had a non-null value, displayName
would take on that value.
Refactoring
You have probably seen code similar to the example below. A couple of API calls returning a value. The value from first call is used as input to the second call. If the value is null, then an exception is thrown.
var resultFromFirstCall = await myApi.PostEntityAsync(requestEntity);
if (resultFromFirstCall == null){
throw new ArgumentNullException("PostEntity Result");
}
var resultFromSecondCall = await myApi.PostResultEntityAsync(resultFromFirstCall);
if (resultFromSecondCall == null){
throw new ArgumentNullException("Result Entity");
}
var resultFromThirdCall = await myApi.PostResultEntityAsync(resultFromSecondCall);
if (resultFromThirdCall == null){
throw new ArgumentNullException("Third Result Entity");
}
The code above could be refactored by using the null coalescing operator instead, which in my opinion makes the code a lot less cluttered and more readable:
var resultFromFirstCall = await myApi.PostEntityAsync(requestEntity) ?? throw new ArgumentNullException("PostEntity Result");
var resultFromSecondCall = await myApi.PostResultEntityAsync(resultFromFirstCall) ?? throw new ArgumentNullException("Result Entity");
var resultFromThirdCall = await myApi.PostResultEntityAsync(resultFromSecondCall) ?? throw new ArgumentNullException("Third Result Entity");
Switch Expressions
C# 8 introduced switch expressions, offering a more concise syntax compared to traditional switch-statements.
string dayOfWeek = day switch
{
0 => "Sunday",
1 => "Monday",
// ... other cases
_ => "Invalid Day" // Default case
};
Using switch expressions like the above not only reduces boilerplate but also returns a value directly.
Transforming Loops to Expressions
Loops are fundamental in C#. However, LINQ (Language Integrated Query) provides expressive methods to perform common operations which would have required loops previously.
Replacing foreach with LINQ
The following example shows how a foreach loop can be replaced with a LINQ query.
List<string> names = new List<string>() { "Alice", "Bob", "Charlie" };
List<string> uppercaseNames = new List<string>();
foreach (var name in names)
{
uppercaseNames.Add(name.ToUpper());
}
// can be replaced by:
List<string> uppercaseNames = names.Select(name => name.ToUpper()).ToList();
Using LINQ for Looping
For loops, especially those that iterate over a range of numbers, can be expressed using LINQ's Enumerable.Range.
for (int i = 1; i <= 10; i++)
{
Console.WriteLine(i);
}
// can be replaced by:
Enumerable.Range(1, 10).ToList().ForEach(Console.WriteLine);
Why Use Expressions Over Traditional Statements?
- Readability: Expressions, especially with LINQ, are often more concise, making code easier to read and understand.
- Maintenance: Reduced lines of code mean fewer places for bugs to hide and less code to maintain.
- Expressiveness: Using expressions can convey intentions more directly, especially with operations like filtering, mapping, and reducing.
In conclusion, while traditional if-statements, switch-statements, and loops have their place, the power of C# expressions allows for cleaner, more readable, and maintainable code. Embracing these patterns can elevate your coding style and improve the overall quality of your applications.
csharp, functional-programming, linq, expressions, refactoring, .net
- Hits: 568