Working with Variables, Operators, and Expressions in Microsoft Visual C#
- 11/18/2015
Using arithmetic operators
C# supports the regular arithmetic operations you learned in your childhood: the plus sign (+) for addition, the minus sign (–) for subtraction, the asterisk (*) for multiplication, and the forward slash (/) for division. The symbols +, –, *, and / are called operators because they “operate” on values to create new values. In the following example, the variable moneyPaidToConsultant ends up holding the product of 750 (the daily rate) and 20 (the number of days the consultant was employed):
long moneyPaidToConsultant; moneyPaidToConsultant = 750 * 20;
Operators and types
Not all operators are applicable to all data types. The operators that you can use on a value depend on the value’s type. For example, you can use all the arithmetic operators on values of type char, int, long, float, double, or decimal. However, with the exception of the plus operator (+), you can’t use the arithmetic operators on values of type string, and you cannot use any of them with values of type bool. So, the following statement is not allowed because the string type does not support the minus operator (subtracting one string from another is meaningless):
// compile-time error Console.WriteLine("Gillingham" - "Forest Green Rovers");
However, you can use the + operator to concatenate string values. You need to be careful because this can have unexpected results. For example, the following statement writes “431” (not “44”) to the console:
Console.WriteLine("43" + "1");
You should also be aware that the type of the result of an arithmetic operation depends on the type of the operands used. For example, the value of the expression 5.0/2.0 is 2.5; the type of both operands is double, so the type of the result is also double. (In C#, literal numbers with decimal points are always double, not float, to maintain as much accuracy as possible.) However, the value of the expression 5/2 is 2. In this case, the type of both operands is int, so the type of the result is also int. C# always rounds toward zero in circumstances like this. The situation gets a little more complicated if you mix the types of the operands. For example, the expression 5/2.0 consists of an int and a double. The C# compiler detects the mismatch and generates code that converts the int into a double before performing the operation. The result of the operation is therefore a double (2.5). However, although this works, it is considered poor practice to mix types in this way.
C# also supports one less-familiar arithmetic operator: the remainder, or modulus, operator, which is represented by the percent sign (%). The result of x % y is the remainder after dividing the value x by the value y. So, for example, 9 % 2 is 1 because 9 divided by 2 is 4, remainder 1.
Examining arithmetic operators
The following exercise demonstrates how to use the arithmetic operators on int values.
Run the MathsOperators project
- Start Visual Studio 2015 if it is not already running.
- Open the MathsOperators project, located in the \Microsoft Press\VCSBS\Chapter 2\MathsOperators folder in your Documents folder.
On the Debug menu, click Start Debugging.
The following form appears:
- In the Left Operand box, type 54.
In the Right Operand box, type 13.
You can now apply any of the operators to the values in the text boxes.
Click the – Subtraction option, and then click Calculate.
The text in the Expression box changes to 54 – 13, but the value 0 appears in the Result box; this is clearly wrong.
Click the / Division option, and then click Calculate.
The text in the Expression box changes to 54/13, and again the value 0 appears in the Result box.
Click the % Remainder button, and then click Calculate.
The text in the Expression box changes to 54 % 13, but, once again, the value 0 appears in the Result text box. Test other combinations of numbers and operators; you will find that they all currently yield the value 0.
- When you have finished, return to Visual Studio and then, on the Debug menu, click Stop Debugging.
As you might have guessed, none of the calculations is currently implemented by the MathsOperators application. In the next exercise, you will correct this.
Perform calculations in the MathsOperators application
- Display the MainPage.xaml form in the Design View window. (In Solution Explorer, in the MathsOperators project, double-click the file MainPage.xaml.)
On the View menu, point to Other Windows, and then click Document Outline.
The Document Outline window appears, showing the names and types of the controls on the form. The Document Outline window provides a simple way to locate and select controls on a complex form. The controls are arranged in a hierarchy, starting with the Page that constitutes the form. As mentioned in Chapter 1, a Universal Windows Platform (UWP) app page contains a Grid control, and the other controls are placed within this Grid. If you expand the Grid node in the Document Outline window, the other controls appear, starting with another Grid (the outer Grid acts as a frame, and the inner Grid contains the controls that you see on the form). If you expand the inner Grid, you can see each of the controls on the form.
If you click any of these controls, the corresponding element is highlighted in the Design View window. Similarly, if you select a control in the Design View window, the corresponding control is selected in the Document Outline window. (To see this in action, pin the Document Outline window in place by deselecting the Auto Hide button in the upper-right corner of the Document Outline window.)
On the form, click the two TextBox controls in which the user types numbers. In the Document Outline window, verify that they are named lhsOperand and rhsOperand.
When the form runs, the Text property of each of these controls holds the values that the user enters.
- Toward the bottom of the form, verify that the TextBlock control used to display the expression being evaluated is named expression and that the TextBlock control used to display the result of the calculation is named result.
- Close the Document Outline window.
- On the View menu, click Code to display the code for the MainPage.xaml.cs file in the Code and Text Editor window.
In the Code and Text Editor window, locate the addValues method. It looks like this:
private void addValues() { int lhs = int.Parse(lhsOperand.Text); int rhs = int.Parse(rhsOperand.Text); int outcome = 0; // TODO: Add rhs to lhs and store the result in outcome expression.Text = $"{lhsOperand.Text} + {rhsOperand.Text}"; result.Text = outcome.ToString(); }
The first statement in this method declares an int variable called lhs and initializes it with the integer corresponding to the value typed by the user in the lhsOperand box. Remember that the Text property of a TextBox control contains a string, but lhs is an int, so you must convert this string to an integer before you can assign it to lhs. The int data type provides the int.Parse method, which does precisely this.
The second statement declares an int variable called rhs and initializes it to the value in the rhsOperand box after converting it to an int.
The third statement declares an int variable called outcome.
A comment stating that you need to add rhs to lhs and store the result in outcome follows. This is the missing bit of code that you need to implement, which you will do in the next step.
The fifth statement uses string interpolation to construct a string that indicates the calculation being performed and assigns the result to the expression.Text property. This causes the string to appear in the Expression box on the form.
The final statement displays the result of the calculation by assigning it to the Text property of the Result box. Remember that the Text property is a string, and the result of the calculation is an int, so you must convert the int to a string before assigning it to the Text property. Recall that this is what the ToString method of the int type does.
Below the comment in the middle of the addValues method, add the following statement (shown below in bold):
private void addValues() { int lhs = int.Parse(lhsOperand.Text); int rhs = int.Parse(rhsOperand.Text); int outcome = 0; // TODO: Add rhs to lhs and store the result in outcome outcome = lhs + rhs; expression.Text = $"{lhsOperand.Text} + {rhsOperand.Text}"; result.Text = outcome.ToString(); }
This statement evaluates the expression lhs + rhs and stores the result in outcome.
Examine the subtractValues method. You should see that it follows a similar pattern. Here you need to add the statement to calculate the result of subtracting rhs from lhs and store it in outcome. Add the following statement (in bold) to this method:
private void subtractValues() { int lhs = int.Parse(lhsOperand.Text); int rhs = int.Parse(rhsOperand.Text); int outcome = 0; // TODO: Subtract rhs from lhs and store the result in outcome outcome = lhs - rhs; expression.Text = $"{lhsOperand.Text} - {rhsOperand.Text}"; result.Text = outcome.ToString(); }
Examine the multiplyValues, divideValues, and remainderValues methods. Again, they are all missing the crucial statement that performs the specified calculation. Add the appropriate statements to these methods (shown in bold).
private void multiplyValues() { int lhs = int.Parse(lhsOperand.Text); int rhs = int.Parse(rhsOperand.Text); int outcome = 0; // TODO: Multiply lhs by rhs and store the result in outcome outcome = lhs * rhs; expression.Text = $"{lhsOperand.Text} * {rhsOperand.Text}"; result.Text = outcome.ToString(); } private void divideValues() { int lhs = int.Parse(lhsOperand.Text); int rhs = int.Parse(rhsOperand.Text); int outcome = 0; // TODO: Divide lhs by rhs and store the result in outcome outcome = lhs / rhs; expression.Text = $"{lhsOperand.Text} / {rhsOperand.Text}"; result.Text = outcome.ToString(); } private void remainderValues() { int lhs = int.Parse(lhsOperand.Text); int rhs = int.Parse(rhsOperand.Text); int outcome = 0; // TODO: Work out the remainder after dividing lhs by rhs and store the result in outcome outcome = lhs % rhs; expression.Text = $"{lhsOperand.Text} % {rhsOperand.Text}"; result.Text = outcome.ToString(); }
Test the MathsOperators application
- On the Debug menu, click Start Debugging to build and run the application.
Type 54 in the Left Operand box, type 13 in the Right Operand box, click the + Addition option, and then click Calculate.
The value 67 should appear in the Result box.
- Click the – Subtraction option, and then click Calculate. Verify that the result is now 41.
- Click the * Multiplication option, and then click Calculate. Verify that the result is now 702.
Click the / Division option, and then click Calculate. Verify that the result is now 4.
In real life, 54/13 is 4.153846 recurring, but this is not real life—this is C# performing integer division. When you divide one integer by another integer, the answer you get back is an integer, as explained earlier.
Click the % Remainder option, and then click Calculate. Verify that the result is now 2.
When dealing with integers, the remainder after dividing 54 by 13 is 2; (54 – ((54/13) * 13)) is 2. This is because the calculation rounds down to an integer at each stage. (My high school math teacher would be horrified to be told that (54/13) * 13 does not equal 54!)
- Return to Visual Studio and stop debugging.
Controlling precedence
Precedence governs the order in which an expression’s operators are evaluated. Consider the following expression, which uses the + and * operators:
2 + 3 * 4
This expression is potentially ambiguous: do you perform the addition first or the multiplication? The order of the operations matters because it changes the result:
- If you perform the addition first, followed by the multiplication, the result of the addition (2 + 3) forms the left operand of the * operator, and the result of the whole expression is 5 * 4, which is 20.
- If you perform the multiplication first, followed by the addition, the result of the multiplication (3 * 4) forms the right operand of the + operator, and the result of the whole expression is 2 + 12, which is 14.
In C#, the multiplicative operators (*, /, and %) have precedence over the additive operators (+ and –), so in expressions such as 2 + 3 * 4, the multiplication is performed first, followed by the addition. The answer to 2 + 3 * 4 is therefore 14.
You can use parentheses to override precedence and force operands to bind to operators in a different way. For example, in the following expression, the parentheses force the 2 and the 3 to bind to the + operator (making 5), and the result of this addition forms the left operand of the * operator to produce the value 20:
(2 + 3) * 4
Using associativity to evaluate expressions
Operator precedence is only half the story. What happens when an expression contains different operators that have the same precedence? This is where associativity becomes important. Associativity is the direction (left or right) in which the operands of an operator are evaluated. Consider the following expression that uses the / and * operators:
4 / 2 * 6
At first glance, this expression is potentially ambiguous. Do you perform the division first or the multiplication? The precedence of both operators is the same (they are both multiplicative), but the order in which the operators in the expression are applied is important because you can get two different results:
- If you perform the division first, the result of the division (4/2) forms the left operand of the * operator, and the result of the whole expression is (4/2) * 6, or 12.
- If you perform the multiplication first, the result of the multiplication (2 * 6) forms the right operand of the / operator, and the result of the whole expression is 4/(2 * 6), or 4/12.
In this case, the associativity of the operators determines how the expression is evaluated. The * and / operators are both left associative, which means that the operands are evaluated from left to right. In this case, 4/2 will be evaluated before multiplying by 6, giving the result 12.
Associativity and the assignment operator
In C#, the equal sign (=) is an operator. All operators return a value based on their operands. The assignment operator = is no different. It takes two operands: the operand on the right side is evaluated and then stored in the operand on the left side. The value of the assignment operator is the value that was assigned to the left operand. For example, in the following assignment statement, the value returned by the assignment operator is 10, which is also the value assigned to the variable myInt:
int myInt; myInt = 10; // value of assignment expression is 10
At this point, you might be thinking that this is all very nice and esoteric, but so what? Well, because the assignment operator returns a value, you can use this same value with another occurrence of the assignment statement, like this:
int myInt; int myInt2; myInt2 = myInt = 10;
The value assigned to the variable myInt2 is the value that was assigned to myInt. The assignment statement assigns the same value to both variables. This technique is useful if you want to initialize several variables to the same value. It makes it very clear to anyone reading your code that all the variables must have the same value:
myInt5 = myInt4 = myInt3 = myInt2 = myInt = 10;
From this discussion, you can probably deduce that the assignment operator associates from right to left. The rightmost assignment occurs first, and the value assigned propagates through the variables from right to left. If any of the variables previously had a value, it is overwritten by the value being assigned.
You should treat this construct with caution, however. One frequent mistake that new C# programmers make is to try to combine this use of the assignment operator with variable declarations. For example, you might expect the following code to create and initialize three variables with the same value (10):
int myInt, myInt2, myInt3 = 10;
This is legal C# code (because it compiles). What it does is declare the variables myInt, myInt2, and myInt3 and initialize myInt3 with the value 10. However, it does not initialize myInt or myInt2. If you try to use myInt or myInt2 in an expression such as
myInt3 = myInt / myInt2;
the compiler generates the following errors:
Use of unassigned local variable 'myInt' Use of unassigned local variable 'myInt2'