HomeSearch

C# if Statement: else if, else

Encode branching logic with if, else-if and else. Evaluate conditions to true or false.
If, else. Consider the present. From this point on, many things may happen. Lightning strikes the ground. A fire starts. An infinite array of possibilities exists.
With an if-statement, we test for a possibility. This statement detects if a condition (an expression) evaluates to true. A number equals 9. We can test for this.
An intro. This program computes the value of an expression. It then tests it in an if-statement. The condition inside the if is evaluated to a boolean value.

True: The value equals 5 and thus the expression evaluates to true. The inner block, with Console.WriteLine, is reached.

Note: In a compiled language, an optimizer can evaluate constants like these even before they are run.

C# program that uses if-statement using System; class Program { static void Main() { int value = 10 / 2; if (value == 5) { Console.WriteLine(true); } } } Output True
True, false. We can specify, and test against, these Boolean literals. And an operator, the unary negation ("!") tests against false directly.True, False

Tip: A test like (value == 10) evaluates to true or false. We can make explicit the comparison against true if we want.

C# program that shows comparison against true using System; class Program { static void Main() { int value = 10; // Every expression in an if-statement must evaluate to true or false. // ... A comparison that is true evaluates to true. if (value == 10) { Console.WriteLine("TRUE"); } if ((value == 10) == true) { Console.WriteLine("TRUE"); } } } Output TRUE TRUE
Else if. What else is there? The else statement. Here, the Test method uses the if-statement with two else-if blocks and one else. The order of the if-statement tests is important.

So: We must test the more restrictive conditions first, or the less restrictive ones will match both cases.

Branches: In this program, the Test method uses several branching instructions expressed in high-level if-statements.

C# program that uses if, else using System; class Program { static void Main() { // Call method with embedded if-statement three times. int result1 = Test(0); int result2 = Test(50); int result3 = Test(-1); // Print results. Console.WriteLine(result1); Console.WriteLine(result2); Console.WriteLine(result3); } static int Test(int value) { if (value == 0) { return -1; } else if (value <= 10) { return 0; } else if (value <= 100) { return 1; } else { return 2; } } } Output -1 1 0
Else. A key question in code, computer science, and the universe is whether to use a return in an else-block. If we omit the else, we lose symmetry.

Here: Method A uses a return statement at the end of an else-block. And method B omits the else-block.

Note: The methods do the same thing. They have equivalent performance and intermediate representations. This comes down to your style.

C# program that shows else constructs using System; class Program { static void Main() { Console.WriteLine(A(5)); Console.WriteLine(B(4)); } static bool A(int y) { if (y >= 5) { return true; } else { return false; } } static bool B(int y) { if (y >= 5) { return true; } return false; } } Output True False
Expressions. The expression in an if-statement must evaluate to true or false. A number result, or a reference type, is not accepted—a compiler error will occur. Expressions can be complex.

Tip: In this program, try changing the values of A and B to 1 and 2. With those values, the if-expressions both evaluate to false.

C# program that uses if, expressions using System; class Program { static void Main() { int a = 1; int b = 3; // Use negated expression. if (!(a == 1 && b == 2)) { Console.WriteLine(true); } // Use binary or version. if (a != 1 || b != 2) { Console.WriteLine(true); } } } Output True True
Brackets are not always required in C# programs. In this example, we use no curly brackets. The bodies of the if-statements are simply the following statements in the source.

Caution: This style is often a bad idea. You cannot add a second line to the body of one of these if-statements.

And: Visual Studio will now insert brackets automatically, so this style of code is not even faster to develop.

C# program that uses no brackets using System; class Program { static void Main() { int value = 1; int size = 2; if (value == 1) if (size == 2) Console.WriteLine("1, 2"); if (value == 0) Console.WriteLine("0"); // Not reached. else Console.WriteLine("Not 0"); // Reached. if (value == 2) Console.WriteLine("2"); // Not reached. } } Output 1, 2 Not 0
Nested. Nesting if-statements will create a similar flow of control to the boolean && operator. The arrangement of if-statements impacts performance.

Method1, Method2: These two methods are identical when compiled. No performance difference will exist.

Method3: This version inverts the order of the checks, so is faster when value > 100.

Note: Nesting ifs can help code clarity. If other statements need to be executed, nesting can also combine logic blocks.

C# program that uses nested ifs using System; class Program { static void Main() { Method1(50); Method2(50); Method3(50); } static void Method1(int value) { if (value >= 10) { if (value <= 100) { Console.WriteLine(true); } } } static void Method2(int value) { if (value >= 10 && value <= 100) { Console.WriteLine(true); } } static void Method3(int value) { if (value <= 100 && value >= 10) { Console.WriteLine(true); } } } Output True True True
Error, cannot convert. The C# compiler returns a compile-time error if we try to compile this program. A variable cannot be assigned within an if-statement. This protects us from typos.
C# program that causes error class Program { static void Main() { int i = 100; // This does not compile! if (i = 200) { System.Console.WriteLine("Zebra"); } } } Output Error CS0029 Cannot implicitly convert type 'int' to 'bool'
Warning, possible mistake. An empty statement is a valid statement to place in an else block. But this is more likely an error in programs—a misplaced semicolon.

Here: We have just a semicolon in the else block. This is valid, and the else clause would be considered empty.

But: This could be a typo, so the C# compiler helpfully warns us with the "possible mistaken empty statement" message.

Tip: Use an empty block with brackets if you wish to have an empty else-statement—no warning will be issued.

C# program that has possible mistaken empty statement class Program { static void Main() { int bird = 2; if (bird == 3) { } else ; } } Output Warning CS0642 Possible mistaken empty statement
Ternary. What is the ternary operator? It is like a question with two answers. It allows us to express a predicate and two consequent statements inside one statement.Ternary Operator

Example: We use the ternary operator in UseTernary(), and the if-else statements in UseIf.

Version 1: This code uses the ternary operator in UseTernary. If the argument is 5, it returns 10, otherwise it returns 20.

Version 2: This version use the if and else statements—the end result is the same as the ternary version.

Internals: The .NET Framework compiles the statements to the same branch statements in most cases (some slight differences can be present).

C# program that shows ternary statement using System; class Program { static void Main() { // Version 1: use ternary. Console.WriteLine("TERNARY: " + UseTernary(5)); Console.WriteLine("TERNARY: " + UseTernary(100)); // Version 2: use if. Console.WriteLine("IF: " + UseIf(5)); Console.WriteLine("IF: " + UseIf(100)); } static int UseTernary(int argument) { return argument == 5 ? 10 : 20; } static int UseIf(int argument) { if (argument == 5) { return 10; } else { return 20; } } } Output TERNARY: 10 TERNARY: 20 IF: 10 IF: 20
Null coalescing. This operator uses two question marks. Similar to ternary, it can only be used on a reference variable. It can reduce source code size.Null Coalescing

Tip: We can replace an if statement that tests against null, or a ternary statement, with a null coalescing expression.

C# program that uses null coalescing operator using System; class Program { static void Main() { // Use null coalescing instead of ternary or if-statements. string value = null; Console.WriteLine(value ?? "NO VALUE"); value = "bird"; Console.WriteLine(value ?? "NO VALUE"); } } Output NO VALUE bird
If optimization, reorder. Suppose a value we want to test in a program is almost always 3. But 1% of the time it is not 3, so we still need to test for 2 and 1. We can test for 3 first.

Tip: When we put the most common matching if-statement first, it becomes faster, but all others become slower. But overall, this is a win.

Here: We pass the value 3 to Method1 and Method2. We test for 3 last in Method1, but first in Method2 (we use the reorder-if optimization).

Result: Testing for the value that is most commonly seen first (in this program, 3) is faster. This can help with chained expressions also.

C# program that uses if-reordering optimization using System; using System.Diagnostics; class Program { const int _max = 1000000; static void Main() { // Version 1: if-statements in non-optimized order. var s1 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { Method1(100, 3); } s1.Stop(); // Version 2: most common match first (reordered ifs). var s2 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { Method2(100, 3); } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); } static int Method1(int max, int testValue) { // Test the argument in a loop. int result = 0; for (int i = 0; i < max; i++) { if (testValue == 1) { result++; } else if (testValue == 2) { result--; } else if (testValue == 3) { result += 2; } } return result; } static int Method2(int max, int testValue) { // Test the argument in a loop, but with most common if first. int result = 0; for (int i = 0; i < max; i++) { if (testValue == 3) { result += 2; } else if (testValue == 1) { result++; } else if (testValue == 2) { result--; } } return result; } } Output 149.84 ns Tests 1, 2, 3 (value is 3) 101.98 ns Reordered, tests 3, 1, 2 (value is 3)
If optimization, table. A lookup table can completely replace an if-else chain. And often this will yield a speedup. A one-to-one mapping of test value to result is easiest to replace.

Here: Version 1 tests for 3 values and sets the result with if-else statements. Version 2 uses a precomputed lookup table.

So: The mapping from test value to result value is the same in each version of the code. But the lookup table consistently is faster.

Tip: This optimization is easiest when each test value has a single result value. A dictionary can also be used as lookup table.

C# program that uses lookup table optimization using System; using System.Diagnostics; class Program { const int _max = 10000000; static void Main() { int[] lookup = new int[] { 10, 50, 7 }; // Version 1: use if, else statements to get a single int result. var s1 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { int test = i % 3; int result = 0; if (test == 0) { result = 10; } else if (test == 1) { result = 50; } else if (test == 2) { result = 7; } if (result == 0) { break; } } s1.Stop(); // Version 2: use lookup table instead of if to get a single int result. var s2 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { int test = i % 3; int result = lookup[test]; if (result == 0) { break; } } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); } } Output 2.92 ns if/else if/else if chain 2.47 ns lookup[test]
If optimization, lookup. Large if-blocks have a lot of indirection and slow a program down. This can be improved with a Dictionary—we can encode the branches in data objects.

Switch: Sometimes a switch statement is faster than an if-statement. But this is a complex issue.

If vs. SwitchSwitch

Dictionary: A Dictionary can be used as a lookup table. This transforms complex if-statements into a single lookup.

Dictionary

Virtual dispatch: Use the type system to add behavior to objects. Place objects in a Dictionary and call their virtual methods.

Virtual
Intermediate language. If-statements are translated into machine code. The intermediate language is a step in this translation. High-level languages provide structured models.

However: These blocks have no meaning to the execution engine. They are instead translated into single instructions in IL.

And: The IL is flat. It is without scope. If-statements are translated to branch instructions.

IL: bne
Research. If the code has a normal, expected path, try not to obscure that path with excessive if-statements. Instead, use ifs for branches from that path. Let's check Code Complete.

Quote: Write your code so that the normal path through the code is clear. Make sure that the rare cases don't obscure the normal path of execution. This is important for both readability and performance (Code Complete).

Paths, continued. If two paths are possible, it is often better to put the common one in the if, and the uncommon one in the else. The more important (common) paths should come first.
In reading code, earlier things are perceived as more important. So put the high-value if-checks first. Some understanding of psychology helps when coding.
Like a river, control flow rushes forward. Ifs cause branches in its path. Branch opcodes are used in low-level representations. With these, the river forks into separate streams.
© 2007-2019 Sam Allen. Every person is special and unique. Send bug reports to info@dotnetperls.com.
Home
Dot Net Perls