left-icon

C# Succinctly®
by Joe Mayo

Previous
Chapter

of
A
A
A

CHAPTER 2

Coding Expressions and Statements

Coding Expressions and Statements


In Chapter 1, you saw how to write, compile, and execute a C# program. The example program had a single statement in the Main method. In this chapter, you’ll learn how to write more statements and add logic to your program. For efficiency, many of the examples in the rest of the book are snippets, but you can still add these statements inside of a Main method to compile and get a better feel for C# syntax. There will be plenty of complete programs too.

Writing Simple Statements

By combining language operators and syntax, you can build expressions and statements in C#. Here are a few examples of simple C# statements.

int count = 7;

char keyPressed = 'Q';

string title = "Weekly Report";

Each of the examples in the previous code listing have common syntactical elements: type, variable identifier, assignment operator, value, and statement completion. The types are int, char, and string, which represent a number, a character, and a sequence of characters respectively. These are a few of the several built-in types that C# offers. Variables are a name that can be used in later code. The = operator assigns the right-hand side of the expression to the left-hand side. Each statement ends with a semicolon.

The previous example showed how to declare a variable and perform assignment at the same time, but that isn’t necessarily required. As long as you declare a variable before trying to use it, you’ll be okay. Here’s a separate declaration.

string title;

And the variable’s later assignment.

title = "Weekly Report";

Note: C# is case sensitive, so “title” and “Title” are two separate variable names.  

Overview of C# Types and Operators

C# is a strongly typed language, meaning that the compiler won’t implicitly convert between incompatible types. For example, you can’t assign a string to an int or an int to a string—at least, not implicitly. The following code will not compile.

int total = "359";

string message = 7;

The “359” with double quotes is a string, and the 7 without quotes is an int. While you can’t perform conversions implicitly, there are ways to do this explicitly. For example, you’ll often receive text input from a user that should be an int or another type. The following code listing shows a couple examples of how to perform such tasks explicitly.

int total = int.Parse("359");

string message = 7.ToString();

In the previous listing, Parse will convert the string to an int if the string represents a valid int. Calling ToString on any value will always produce a string that will compile.

In addition to the previous conversion examples, C# has a cast operator that lets you convert between types that allow explicit conversions. Let’s say you have a double, which is a 64-bit floating point type, and want to assign that to an int, which is a 32-bit whole number. You could cast it like this:

double preciseLength = 5.61;

int roundedLength = (int)preciseLength;

Without the cast operator, you would receive a compiler error because a double is not an int. Essentially, the C# compiler is protecting you from shooting yourself in the foot because assigning a double to an int means that you lose precision. In the previous example, roundedLength becomes 5. Using the cast operator allows you to tell the C# compiler that you know this operation could be dangerous in the wrong circumstances, but makes sense for your particular situation.

The following table lists the built-in types so you can see what is available:

Table 1: Built-In Types

Type (Literal Suffix)

Description

Values/Range

Byte

8-bit unsigned integer

0 to 255

Sbyte

8-bit signed integer

-128 to 127

Short

16-bit signed integer

-32,768 to 32,767

Ushort

16-bit unsigned integer

0 to 65,535

Int

32-bit signed integer

-2,147,483,648 to 2,147,483,647

Uint

32-bit unsigned integer

0 to 4,294,967,295

long (l)

64-bit signed integer

–9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

ulong (ul)

64-bit unsigned integer

0 to 18,446,744,073,709,551,615

float (f)

32-bit floating point

-3.4 × 1038 to +3.4 × 1038

double (d)

64-bit floating point

±5.0 × 10−324 to ±1.7 × 10308

decimal (m)

128-bit, 28 or 29 digits of precision (ideal for financial)

(-7.9 × 1028 to 7.9 x 1028) / (100 to 28)

Bool

Boolean

true or false

Char

16-bit Unicode character (use single quotes)

U+0000 to U+FFFF  

String

Sequence of Unicode characters (use double quotes)

E.g., “abc”

You should add a suffix to a number when the meaning would be ambiguous. In the following example, the m suffix ensures the 9.95 literal is treated as a decimal number:

decimal price = 9.95m;

You can assign Unicode values directly to a char. The following example shows how to assign a carriage return.

char cr = '\u0013';

You can also obtain the Unicode value of a character with a cast operator as shown here.

int crUnicode = (int)cr;

So far, you’ve only seen statements with the assignment operator, but C# has many other operators that allow you to perform all of the logical operations you would expect of any general purpose programming language. The following table lists some of the available operators.

Table 2: C# Operators

Category

Description

Primary

x.y  x?.y  f(x)  a[x]  x++  x--  new  typeof  default  checked  unchecked   nameof

Unary

+  -  !  ~  ++x  --x  (T)x  await x

Multiplicative

*  /  %

Additive

+  -

Shift

<<  >>

Relational and Type Testing

<  >  <=  >=  is  as

Equality

==  !=

Logical AND

&

Logical XOR

^

Logical OR

|

Conditional AND

&&

Conditional OR

||

Null Coalescing

??

Conditional

?:

Assignment

=  *=  /=  %=  +=  -=  <<=  >>=  &=  ^=  |=  =>

Prefix operators change the value of the variable before assignment, and postfix operators change a variable after assignment, as demonstrated in the following sample.

int val1 = 5;

int val2 = ++val1;

int val3 = 2;

int val4 = val3--;

In the previous code listing, both val1 and val2 are 6. The val3 variable is 1, but val4 is 2 because the postfix operator evaluates after assignment.

The ternary operator offers simple syntax for if-then-else logic. Here’s an example:

decimal priceGain = 2.5m;

string action = priceGain > 2m ? "Buy" : "Sell";

On the left side of ? is a Boolean expression, priceGain > 2m. If that is true, which it is in this example, the ternary operator returns the first value between ? and :, which is "Buy". Otherwise, the ternary operator would return the value after the :, which is "Sell". This statement assigns the result of the ternary operator, "Buy", to the string variable, action.

In addition to the built-in types, the FCL has many types you will use on a daily basis. One of these is DateTime, which represents a date and time. Here’s a quick demo showing a couple things you can do with a DateTime.

DateTime currentTime = DateTime.Now;

string shortDateString = currentTime.ToShortDateString();

string longDateString = currentTime.ToLongDateString();

string defaultDateString = currentTime.ToString();

DateTime tomorrow = currentTime.AddDays(1);

The previous code shows how to get the current DateTime, a short representation of a date (e.g., 12/8/2014), a long representation of the date and time (everything spelled out), the default numeric representation, and how to use DateTime methods for calculations.

Tip: Search the FCL before creating your own library of types. Many of the common types you use every day, like DateTime, will already exist.

Operator Precedence and Associativity

The C# operators listed in Table 2 outlines operators in their general order of precedence. The precedence defines which operators evaluate first. Operators of higher precedence evaluate before operators of lower precedence.

Assignment and conditional operators are right-associative and all other operators are left-associative. You can change the normal order of operations by using parentheses as shown in the following code listing.

int result1 = 2 + 3 * 5;

int result2 = (2 + 3) * 5;

In the previous code, result1 is 17, but result2 is 25.

Formatting Strings

There are different ways to build and format strings in C#: concatenation, numeric format strings, or string interpolation. The following code listing demonstrates string concatenation.

string name = "Joe";

string helloViaConcatenation = "Hello, " + name + "!";

Console.WriteLine(helloViaConcatenation);

This prints “Hello, Joe!” to the console. The following example does the same thing, but uses string.Format.

string helloViaStringFormat = string.Format("Hello, {0}!", name);

Console.WriteLine(helloViaStringFormat);

The string.Format takes a format string that has numeric placeholders in curly braces. It’s 0-based, so the first placeholder is {0}. The parameters following the string are placed into the format string in the order they appear. Since name is the first (and only) parameter, string.Format replaces {0} with Joe to create "Hello, Joe!" as a string. As a convenience in console applications, WriteLine uses the same formatting. The following code accomplishes the same task as the two lines in the previous code listing.

Console.WriteLine("Hello, {0}!", name);

Going a little further, string formatting is more powerful, allowing you to specify column lengths, alignment, and value formatting as shown in the following code.

string item = "bread";

decimal amount = 2.25m;

Console.WriteLine("{0,-10}{1:C}", item, amount);

In this example, the first placeholder consumes 10 characters in length. The default alignment is right, but the minus sign changes that to align on the left. On the second placeholder, the C is a currency format string.

Note: There are many string formatting options. You can visit https://msdn.microsoft.com/en-us/library/dwhawy9k(v=vs.110).aspx for standard formats, https://msdn.microsoft.com/en-us/library/0c899ak8(v=vs.110).aspx for custom formats, and https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx for DateTime formats.

C# 6 introduced a new way to format strings, called string interpolation. It’s a shorthand syntax that lets you replace numeric placeholders with expressions as follows:

Console.WriteLine($"{item}      {amount}");

The $ prefix is required. Here, the value from the item variable replaces {item} and the value from the amount variable replaces {amount}. Similar to numeric placeholders, you can include additional formatting.

Console.WriteLine($"{nameof(item)}: {item,-10} {nameof(amount)}: {amount:C}");

The nameof operator prints out the name “item”, demonstrating how you can use expressions in placeholders. You can also see the space and currency formatting on item and amount.

Branching Statements

You can use either an if—else or switch statement in your code for branching logic. When you only need to execute code for a true condition, use an if statement as in the following sample.

string action2 = "Sell";

if (priceGain > 2m)

{

    action2 = "Buy";

}

The curly braces are optional in this example because there is only one statement to execute if priceGain > 2m. However, they would be required for multiple statements. This is true for all branching and logic statements. You can also have an else case, as shown in the following listing.

string action3 = "Do Nothing";

if (priceGain <= 2m)

{

    action3 = "Sell";

}

else

{

    action3 = "Buy";

}

Whenever the Boolean condition of the if statement is false, as it is in the previous code sample where priceGain <= 2m, the else clause executes. In this case, action3 becomes "Buy". Of course, you can have multiple conditions by adding more else if clauses.

string action4 = null;

if (priceGain <= 2m)

{

    action4 = "Sell";

}

else if (priceGain > 2m && priceGain <= 3m)

{

    action4 = "Do Nothing";

}

else

{

    action4 = "Sell";

}

In the previous example, you can see a more complex Boolean expression in the else if clause. When priceGain is 2.5, the value of action4 becomes "Do Nothing". The && is a logical operator that succeeds if both the expression on the left and right are true. The logical || operator succeeds if either the expression on the left or right is true. These operators also perform short-circuit operations where the expression on the right doesn’t execute if the expression on the left causes the whole expression to not be true. In the case of the else if in Code Listing 25, if priceGain were 2m or less, the && operator would not evaluate the priceGain <= 3 expression because the entire operation is already false. Once a branch of the if statement executes, no other branches are evaluated or executed.

Notice that I set action4 to null. The null keyword means no value. I’ll talk about null in the next chapter and explain where you can use it.

An if statement is good for either simple branching or complex conditions, such as the previous else if clause. However, when you have multiple cases and all expressions are constant values, such as an int or string, you might prefer a switch statement. The following example uses a switch statement to select appropriate equipment based on a weather forecast.

string currentWeather = "rain";

string equipment = null;

switch (currentWeather)

{

    case "sunny":

        equipment = "sunglasses";

        break;

    case "rain":

        equipment = "umbrella";

        break;

    case "cold":

    default:

        equipment = "jacket";

        break;

}

The switch statement tries to match a value, currentWeather in this example, with one of its case statements. It uses the default case for no match. All case statements must be terminated with a break statement. The only time fall-through is allowed is when a case has no body, as demonstrated with the "cold" case and default, which both set equipment to "jacket". Since currentWeather is "rain", equipment becomes "umbrella" and no other cases execute.

Beyond branching statements, you also need the ability to perform a set of operations multiple times, which is where C# loops come in. Before discussing loops, let’s look at arrays and collections, which hold data that loops can use.

Arrays and Collections

Sometimes you need to group a number of items together in a collection to manage them in memory. For this, you can either use arrays or one of the many collection types in the .NET Framework. The following sample demonstrates how to create an array.

int[] oddNumbers = { 1, 3, 5 };

int firstOdd = oddNumbers[0];

int lastOdd = oddNumbers[2];

Here, I’ve declared and initialized the array with three values. Arrays and collections are 0-based, so firstOdd is 1 and lastOdd is 5. The [x] syntax, where x is a number, is referred to as an indexer because it allows you to access the array at the location specified by the index. Here’s another example that uses string instead of int.

string[] names = new string[3];

names[1] = "Joe";

In this example, I instantiated an array to hold three strings. All of the strings equal null by default. This code sets the second string to "Joe".

In addition to arrays, you can use all types of data structures, such as List, Stack, Queue, and more, which are part of the FCL. The following example shows how to use a List. Remember to add a using clause for System.Collections.Generic to use the List<T> type.

List<decimal> stockPrices = new List<decimal>();

stockPrices.Add(56.23m);

stockPrices.Add(72.80m);

decimal secondStockPrice = stockPrices[1];

In this sample, I instantiated a new List collection. The <decimal> is a generic type indicating that this is a strongly typed list that can only hold values of type decimal; it’s a List of decimal. That list has two items. Notice how I used the array-like indexer syntax to read the second item in the (0-based) stockPrices list.

Looping Statements

C# supports several loops, including for, foreach, while, and do. The code listings that follow perform similar logic.

double[] temperatures = { 72.3, 73.8, 75.1, 74.9 };

for (int i = 0; i < temperatures.Length; i++)

{

    Console.WriteLine(i);

}

The for loop initializes i to 0, makes sure i is less than the number of items in the temperature array, executes the Console.WriteLine, and then increments i. It continues executing until the condition (i < temperatures.Length) is false, and then moves on to the next statement in the program.

foreach (int temperature in temperatures)

{

    Console.WriteLine(temperature);

}

The foreach loop used in Code Listing 31 is simpler and will execute for each value in the temperatures array.

Next is an example of a while loop.

int tempCount = 0;

while (tempCount < temperatures.Length)

{

    Console.WriteLine(tempCount);

    tempCount++;

}

The while loop evaluates the condition and executes if it’s true. Notice that I initialized tempCount to 0 and increment tempCount inside of the loop on each iteration.

Finally, the following example shows how to write a do-while loop.

int tempCount2 = 0;

do

{

    Console.WriteLine(tempCount2++);

}

while (tempCount2 <= temperatures.Length);

A do-while loop is good for when you want to execute logic at least one time. This example increments tempCount2 as a parameter to Console.WriteLine. Remember, the postfix operator changes the variable after evaluation.

Wrapping Up

Here’s a calculator program that pulls together some of the concepts from this chapter, plus some extra features. You can type this into your editor and execute it for practice.

using System;

using System.Text;

/*

    Title: Calculator

    By: Joe Mayo

*/

class Calculator

{

    /// <summary>

    /// This is the entry point.

    /// </summary>

    static void Main()

    {

        char firstChar = 'Q';

        bool keepRunning = true;

        do

        {

            Console.WriteLine();

            Console.Write("What do you want to do? (Add, Subtract, Multiply, Divide, Quit): ");

            string input = Console.ReadLine();

            firstChar = input[0];

            // This is used in both the if statement and the do-while loop.

            keepRunning = !(firstChar == 'q' || firstChar == 'Q');

            double firstNumber = 0;

            double secondNumber = 0;

            if (keepRunning)

            {

                Console.Write("First Number: ");

                string firstNumberInput = Console.ReadLine();

                firstNumber = double.Parse(firstNumberInput);

                Console.Write("Second Number: ");

                string secondNumberInput = Console.ReadLine();

                secondNumber = double.Parse(secondNumberInput);

            }

            double result = 0;

            switch (firstChar)

            {

                case 'a':

                case 'A':

                    result = firstNumber + secondNumber;

                    break;

                case 's':

                case 'S':

                    result = firstNumber - +secondNumber;

                    break;

                case 'm':

                case 'M':

                    result = firstNumber * secondNumber;

                    break;

                case 'd':

                case 'D':

                    result = firstNumber / secondNumber;

                    break;

                default:

                    result = -1;

                    break;

            }

            Console.WriteLine();

            Console.WriteLine("Your result is " + result);

        } while (keepRunning);

    }

}

The previous program demonstrates a do-while loop, an if statement, a switch statement, and a basic console communication with the user.

There are a couple string features here that you haven’t seen yet. The first is where the program uses Console.ReadLine to read input text from the user for the input string. Notice the indexer syntax to read the first character from the string. You can read any character of a string this way. Also, look at the bottom of the program where it prints "Your result is " + result, which concatenates a string with the number. Using the + operator for concatenation is a simple way to build strings. Another way to build a string is with a type named StringBuilder, which you can use like this:

StringBuilder sb = new StringBuilder();

sb.Append("Your result is ");

sb.Append(result.ToString());

Console.WriteLine(sb.ToString());

You’ll also need to add a using System.Text; clause to the top of the file. After you’ve used the concatenate operator, +, about four times on the same string, you might consider rewriting with a StringBuilder instead. The string type is immutable, meaning that you can’t modify it. This also means that every concatenation operation causes the CLR to create a new string in-memory.

The calculator program also has multiline and single-line comments that aren’t compiled, but help you document the code as you need. Here’s the multi-line comment:

/*

    Title: Calculator

    By: Joe Mayo

*/

Here’s the single-line comment:

// This is used in both the if statement and the do-while loop.

An extension of the single-line comment is a convention that uses three slashes and a set of XML tags, known as documentation comments.

/// <summary>

/// This is the entry point.

/// </summary>

Summary

C# has a full set of operators and types that allow you to write a wide range of expressions and statements. With branching statements and loops, you can write logic of your choosing. All of the code in this chapter has been in the Main method, but clearly that’s inadequate and you’ll quickly grow out of that. The next chapter explores some new C# features to help organize code with methods and properties.

Scroll To Top
Disclaimer
DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.