C# Operators
Results are computed by building expressions. These expressions are built by combining variables and operators together into statements. The following table describes the allowable operators, their precedence, and associativity.
Table 2-4. Operators with their precedence and Associativity
Category (by precedence)
|
Operator(s)
|
Associativity
|
Primary
|
x.y f(x) a[x] x++ x-- new typeof default checked unchecked delegate
|
left
|
Unary
|
+ - ! ~ ++x --x (T)x
|
right
|
Multiplicative
|
* / %
|
left
|
Additive
|
+ -
|
left
|
Shift
|
<< >>
|
left
|
Relational
|
< > <= >= is as
|
left
|
Equality
|
== !=
|
right
|
Logical AND
|
&
|
left
|
Logical XOR
|
^
|
left
|
Logical OR
|
|
|
left
|
Conditional AND
|
&&
|
left
|
Conditional OR
|
||
|
left
|
Null Coalescing
|
??
|
left
|
Ternary
|
?:
|
right
|
Assignment
|
= *= /= %= += -= <<= >>= &= ^= |= =>
|
right
|
Left associativity means that operations are evaluated from left to right. Right associativity mean all operations occur from right to left, such as assignment operators where everything to the right is evaluated before the result is placed into the variable on the left.
Most operators are either unary or binary. Unary operators form expressions on a single variable, but binary operators form expressions with two variables. Listing 2-2 demonstrates how unary operators are used.
Listing 2-2. Unary Operators: Unary.cs
using System;
class Unary
{
public static void Main()
{
int unary = 0;
int preIncrement;
int preDecrement;
int postIncrement;
int postDecrement;
int positive;
int negative;
sbyte bitNot;
bool logNot;
preIncrement = ++unary;
Console.WriteLine("pre-Increment: {0}", preIncrement);
preDecrement = --unary;
Console.WriteLine("pre-Decrement: {0}", preDecrement);
postDecrement = unary--;
Console.WriteLine("Post-Decrement: {0}", postDecrement);
postIncrement = unary++;
Console.WriteLine("Post-Increment: {0}", postIncrement);
Console.WriteLine("Final Value of Unary: {0}", unary);
positive = -postIncrement;
Console.WriteLine("Positive: {0}", positive);
negative = +postIncrement;
Console.WriteLine("Negative: {0}", negative);
bitNot = 0;
bitNot = (sbyte)(~bitNot);
Console.WriteLine("Bitwise Not: {0}", bitNot);
logNot = false;
logNot = !logNot;
Console.WriteLine("Logical Not: {0}", logNot);
}
}
class Unary
{
public static void Main()
{
int unary = 0;
int preIncrement;
int preDecrement;
int postIncrement;
int postDecrement;
int positive;
int negative;
sbyte bitNot;
bool logNot;
preIncrement = ++unary;
Console.WriteLine("pre-Increment: {0}", preIncrement);
preDecrement = --unary;
Console.WriteLine("pre-Decrement: {0}", preDecrement);
postDecrement = unary--;
Console.WriteLine("Post-Decrement: {0}", postDecrement);
postIncrement = unary++;
Console.WriteLine("Post-Increment: {0}", postIncrement);
Console.WriteLine("Final Value of Unary: {0}", unary);
positive = -postIncrement;
Console.WriteLine("Positive: {0}", positive);
negative = +postIncrement;
Console.WriteLine("Negative: {0}", negative);
bitNot = 0;
bitNot = (sbyte)(~bitNot);
Console.WriteLine("Bitwise Not: {0}", bitNot);
logNot = false;
logNot = !logNot;
Console.WriteLine("Logical Not: {0}", logNot);
}
}
When evaluating expressions, post-increment (x++) and post-decrement (x--) operators return their current value and then apply the operators. However, when using pre-increment (++x) and pre-decrement (--x) operators, the operator is applied to the variable prior to returning the final value.
In Listing 2-2, the unary variable is initialized to zero. When the pre-increment (++x) operator is used, unary is incremented to 1 and the value 1 is assigned to the preIncrement variable. The pre-decrement (--x) operator turns unary back to a 0 and then assigns the value to the preDecrement variable.
When the post-decrement (x--) operator is used, the value of unary, 0, is placed into the postDecrement variable and then unary is decremented to -1. Next the post-increment (x++) operator moves the current value of unary, -1, to the postIncrement variable and then increments unary to 0.
The variable bitNot is initialized to 0 and the bitwise not (~) operator is applied. The bitwise not (~) operator flips the bits in the variable. In this case, the binary representation of 0, "00000000", was transformed into -1, "11111111".
While the (~) operator works by flipping bits, the logical negation operator (!) is a logical operator that works on bool values, changing true to false or false to true. In the case of the logNot variable in Listing 2-2, the value is initialized to false, and the next line applies the logical negation operator, (!), which returns true and reassigns the new value, true, to logNot. Essentially, it is toggling the value of the bool variable, logNot.
The setting of positive is a little tricky. At the time that it is set, the postIncrement variable is equal to -1. Applying the minus (-) operator to a negative number results in a positive number, meaning that positive will equal 1, instead of -1. The minus operator (-), which is not the same as the pre-decrement operator (--), doesn't change the value of postInc - it just applies a sign negation. The plus operator (+) doesn't affect the value of a number, assigning negative with the same value as postIncrement, -1.
Notice the expression (sbyte)(~bitNot). Any operation performed on types sbyte, byte, short, or ushort return int values. To assign the result into the bitNot variable we had to use a cast, (Type), operator, where Type is the type you wish to convert to (in this case - sbyte). The cast operator is shown as the Unary operator, (T)x, in table 2-4. Cast operators must be performed explicity when you go from a larger type to a smaller type because of the potential for lost data. Generally speaking, assigning a smaller type to a larger type is no problem, since the larger type has room to hold the entire value. Also be aware of the dangers of casting between signed and unsigned types. You want to be sure to preserve the integrity of your data. Many basic programming texts contain good descriptions of bit representations of variables and the dangers of explicit casting.
Here's the output from the Listing 2-2:
pre-Increment: 1
pre-Decrement 0
Post-Decrement: 0
Post-Increment: -1
Final Value of Unary: 0
Positive: 1
Negative: -1
Bitwise Not: -1
Logical Not: true
In addition to unary operators, C# has binary operators that form expressions of two variables. Listing 2-3 shows how to use the binary operators.
Listing 2-3. Binary Operators: Binary.cs
usingSystem;
classBinary
{
public static void Main()
{
int x, y, result;
float floatresult;
x = 7;
y = 5;
result = x+y;
Console.WriteLine("x+y: {0}", result);
result = x-y;
Console.WriteLine("x-y: {0}", result);
result = x*y;
Console.WriteLine("x*y: {0}", result);
result = x/y;
Console.WriteLine("x/y: {0}", result);
floatresult = (float)x/(float)y;
Console.WriteLine("x/y: {0}", floatresult);
result = x%y;
Console.WriteLine("x%y: {0}", result);
result += x;
Console.WriteLine("result+=x: {0}", result);
}
}
classBinary
{
public static void Main()
{
int x, y, result;
float floatresult;
x = 7;
y = 5;
result = x+y;
Console.WriteLine("x+y: {0}", result);
result = x-y;
Console.WriteLine("x-y: {0}", result);
result = x*y;
Console.WriteLine("x*y: {0}", result);
result = x/y;
Console.WriteLine("x/y: {0}", result);
floatresult = (float)x/(float)y;
Console.WriteLine("x/y: {0}", floatresult);
result = x%y;
Console.WriteLine("x%y: {0}", result);
result += x;
Console.WriteLine("result+=x: {0}", result);
}
}
And here's the output:
x+y: 12
x-y: 2
x*y: 35
x/y: 1
x/y: 1.4
x%y: 2
result+=x: 9
Listing 2-3 shows several examples of binary operators. As you might expect, the results of addition (+), subtraction (-), multiplication (*), and division (/) produce the expected mathematical results.
The floatresult variable is a floating point type. We explicitly cast the integer variables x and y to calculate a floating point value.
There is also an example of the remainder(%) operator. It performs a division operation on two values and returns the remainder.
The last statement shows another form of the assignment with operation (+=) operator. Any time you use the assignment with operation operator, it is the same as applying the binary operator to both the left hand and right hand sides of the operator and putting the results into the left hand side. The example could have been written as result = result + x; and returned the same value.
Checked and Unchecked Operator
The checked keyword is used to control the overflow-checking context for integral-type arithmetic operations and conversions. It can be used as an operator or a statement according to the following forms.
The checked statement:
The checked statement:
checked block
The statement block that contains the expressions to be evaluated in a checked context.
The checked operator:
checked (expression)
The expression to be evaluated in a checked context. Notice that the expression must be in parentheses ( ).
Unchecked
The unchecked keyword is used to control the overflow-checking context for integral-type arithmetic operations and conversions. It can be used as an operator or a statement according to the following forms.The unchecked statement :
unchecked block
The statement block that contains the expressions to be evaluated in an unchecked context.
The unchecked operator :
The unchecked operator :
unchecked (expression)
The expression to be evaluated in an unchecked context