Tải bản đầy đủ (.pdf) (24 trang)

Operators, Assignments, and Expressions

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (390.79 KB, 24 trang )

chapter
5
Operators, Assignments, and
Expressions
O
perators, assignments, and expressions are the rudimentary building blocks of
those programming languages whose design is driven in large part by the underlying
architecture of the von Neumann machine. And C# is no exception.
An expression in its most basic form is simply a literal or a variable. Larger expres-
sions are formed by applying an operator to one or more operands (or expressions). Of all
operators, the most fundamental is the assignment operator that stores the result of an
expression in a variable. Because variables are expressions themselves, they can be used
as operands in other expressions and hence, propel a computation forward.
In this chapter, we present all variations of the arithmetic, conditional, relational,
and assignment operators in C#. We discuss which simple types and objects are valid for
each operator and what types and values are generated for each expression. Because most
operators in C# are derived from the lexicon of C/C++, explanations are relatively short
but always augmented with simple examples. To disambiguate the order of expression
evaluation, the rules of precedence and associativity are also presented along with the
powerful notion of operator overloading that was first introduced in Chapter 3.
5.1 Operator Precedence and Associativity
An expression in C# is a combination of operands and operators and is much like expres-
sions in C. An operand is a literal or a variable, and an operator acts upon the operands
to return to a single value. Table 5.1 lists all the operators in order of precedence from
highest (Primary) to lowest (Assignment). Operators with the same precedence appear on
the same line of the table. However, before presenting the operators starting from those
83
84
Chapter 5: Operators, Assignments, and Expressions

Category Operators Associativity


Primary (Highest) x.y f(x) a[x] x++ x-- (x) new →
typeof sizeof checked unchecked
Unary +-˜!++x--x(Type)x ←
Multiplicative */% →
Additive +- →
Shift << >> →
Relational/Type Testing <<=>>=isas →
Equality == != →
Logical AND & →
Logical XOR ˆ →
Logical OR | →
Conditional Logical AND && →
Conditional Logical OR || →
Null Coalescing ?? ←
Conditional ?: →
Assignment =+=-=*=/=%=|=ˆ=&=>>=<<= ←
Table 5.1: Precedence and associativity rules for all operators in C#.
with the lowest precedence, we pause to explain the rules for “deterministic” evaluation,
namely the rules of precedence and associativity.
Precedence rules determine which operator should be applied first. For operators
with different precedence, the one with the highest precedence is always applied first. For
example, a+b*c is evaluated as a+(b*c). Associativity rules, on the other hand, deter-
mine which operator should be applied first among operators with the same precedence.
There are two kinds of associativity:

Left associativity groups operators from left to right (→). For example, a+b-c
is evaluated as ((a+b)-c).

Right associativity groups operators from right to left (←). For example,
a=b=c is evaluated as (a=(b=c)).

Later in this chapter we will cover why the order of evaluation is important if expressions
have side effects and short circuits.
5.2 Assignment Operators
5.2.1 Simple Assignment
The assignment operator with the following syntax assigns the result of the expression
on the right-hand side to the variable on the left-hand side:
EBNF
Variable "=" Expression .

5.2 Assignment Operators
85
The destination Variable and the source Expression must be type compatible. The
Variable can store either a simple data value or an object reference.
Assignments of Simple Values
Examples:
int a, b, c;
a=1; //OK.
b=a; //OK.
a = c; // Error: Variable must be initialized before used.
1 = a; // Error: Destination must be a variable.
c = (a + b); // OK.
(a + b) = c; // Error: Destination must be a variable.
The assignment operator has the lowest precedence, allowing the expression on the right-
hand side to be evaluated before any assignment:
int a;
a=1;
System.Console.WriteLine(a);
a=a-1; //-hashigher precedence than =
System.Console.WriteLine(a);
a=2+a*3; //(2+(0*3))

System.Console.WriteLine(a);
Output:
1
0
2
Assignments of References
Examples:
Id id1 = new Id("Frank", 1);
Id id2 = new Id("Emma", 2);
id2 = id1;
Copying references by assignment does not copy the content of the source object, only
its reference. Now id2 refers to the same Id object as id1, and the previous object
Id("Emma", 2) is eligible for garbage collection.
86
Chapter 5: Operators, Assignments, and Expressions

5.2.2 Multiple Assignments
An assignment always returns the value of the expression on the right-hand side as a result.
Therefore, initializing several variables to a common value or reference using multiple
assignment statements:
int a, b, c;
a=1;b=1;c=1;
can be reduced to a single statement using multiple assignments as shown:
a=b=c=1; //a=(b=(c=1));
The preceding example illustrates the importance of right associativity for the assignment
operator.
5.3 Conditional Operator
The conditional operator evaluates a boolean expression, and, depending on its
resultant value (either true or false), executes one of two expressions as defined here:
EBNF

ConditionalOperator = Condition "?" ExprIfConditionTrue ":" ExprIfConditionFalse.
The conditional operator, therefore, is equivalent to a simple if-else statement:
if ( Condition )
ExprIfConditionTrue
else
ExprIfConditionFalse
For example:
minimum=a<b?a:b;
is equivalent to:
if (a < b)
minimum = a;
else
minimum = b;
Another example:
absolute=a<0?-a:a;

5.4 Null Coalescing Operator
87
is equivalent to:
if (a < 0)
absolute = -a;
else
absolute = a;
This operator can be nested but becomes rapidly unreadable:
a?b?c:d:e // Evaluates as (a?(b?c:d):e)
5.4 Null Coalescing Operator
Given that a represents an operand of a nullable or reference type, the null coalescing
operator is defined as in Table 5.2.
Name Notation Meaning
Null Coalescing a??b Returns a if a is non-null, otherwise returns b.

Table 5.2: Null coalescing operator.
Example:
using System;
public class CoalescingNull {
public static void Main(string[] args) {
bool? a = true;
bool? b = false;
object o = null;
Console.WriteLine("|{0,4}|{1,4}|{2,4}|{3,4}|",
a??b, a??o, o??b, o??o );
}
}
Output:
|True|True|False| |
88
Chapter 5: Operators, Assignments, and Expressions

5.5 Conditional Logical Operators
Given that a and b represent boolean expressions, the conditional logical operators are
defined as in Table 5.3.
Name Notation Meaning
Conditional Logical AND a && b true if both operands are true, otherwise false
Conditional Logical OR a || b true if either or both operands are true,
otherwise false
Conditional Logical NOT !a true if the operand is false, otherwise false
Table 5.3: Conditional logical operators.
These operators are much like logical (bitwise) operators except that their evaluation
is short-circuited. The short-circuit eliminates unnecessary evaluations. If the value of
a is false then the expression a&&balso evaluates to false without the need to
evaluate b. Similarly, if the value of a is true then the expression a||balso evaluates

to true without the need to evaluate b. Table 5.4 summarizes all combinations of boolean
values.
a b a&&b a||b
true true true true
true false false true
false true false true
false false false false
Table 5.4: Values for conditional logical operators.
Example:
using System;
public class ConditionalLogical {
public static void Main(string[] args) {
bool t, b, f = false;
t=b=true;
Console.WriteLine( (t && t) +" "+ (t && f) +" "+ (f && t) +" "+
(f && f) );
Console.WriteLine( (t || t) +" "+ (t || f) +" "+ (f || t) +" "+
(f || f) );

5.6 Logical Operators
89
// t&&b where f not evaluated (short-circuited)
Console.Write("{0} ", t&&b || f );
// f || b where t not evaluated (short-circuited)
Console.Write("{0} ", f&&t || b );
// f || f where b not evaluated (short-circuited)
Console.Write("{0} ", f || f&&b );
// t&&b where f not evaluated (short-circuited)
Console.WriteLine("{0}", f || t&&b );
}

}
Output:
True False False False
True True True False
True True False True
5.6 Logical Operators
Given that a and b are corresponding bit values in the left-hand and right-hand operands,
respectively, the logical (bitwise) operators are defined as in Table 5.5.
Name Notation Meaning
Logical NOT ˜a Invert the bit value (Complement)
Logical AND a&b 1 if both bits are 1, otherwise 0
Logical OR a|b 1 if either or both bits are 1, otherwise 0
Logical XOR aˆb 1 if and only if one of the bits is 1, otherwise 0
Table 5.5: Logical operators.
a b ˜a a&b a|b aˆb
11 0 1 1 0
10 0 0 1 1
01 1 0 1 1
001000
Table 5.6: Values for logical operators.
90
Chapter 5: Operators, Assignments, and Expressions

Valid types for logical operators are integers and boolean.
Example:
public class LogicalBitwise {
public static void Main(string[] args) {
ushort a = 0x005A; // in binary = 0000 0000 0101 1010
ushort b = 0x3C5A; // in binary = 0011 1100 0101 1010
System.Console.WriteLine( "{0:x}", a&b);

System.Console.WriteLine( "{0:x}", a|b);
System.Console.WriteLine( "{0:x}", aˆb);
System.Console.WriteLine( "{0:x}", ˜a );
System.Console.WriteLine( "{0:x}", ˜b );
}
}
Output:
5a
3c5a
3c00
ffffffa5
ffffc3a5
5.6.1 Logical Operators as Conditional Logical Operators
The logical bitwise operators may also be used as conditional logical operators since they
can be applied to boolean operands and return a bool value. Given that a and b represent
boolean expressions, the logical operators are defined as in Table 5.7.
Name Notation Meaning
Logical NOT !a Returns the complement of the truth value of a (negation)
Logical AND a & b true if both operands are true, otherwise false
Logical OR a | b true if either or both operands are true, otherwise false
Logical XOR a ˆ b true if and only if one operand is true, otherwise false
Table 5.7: Logical operators as conditional logical operators.
Note that the logical operators & and | have the same truth values as their corresponding
conditional operators, && and || (Table 5.8).

5.6 Logical Operators
91
a b !a a&b a|b aˆb
true true false true true false
true false false false true true

false true true false true true
false false true false false false
Table 5.8: Values for logical operators.
5.6.2 Compound Logical Assignment Operators
Given that a and b represent integral expressions, the compound logical assignment
operators are defined as in Table 5.9.
Name Notation Meaning
Compound Logical AND b &= a b = (Type) (b & (a))
Compound Logical OR b |= a b = (Type) (b | (a))
Compound Logical XOR b ˆ= a b = (Type) (b ˆ (a))
Table 5.9: Compound logical assignment operators.
Based on the preceding table, a and b are first promoted to int and the result is implicitly
narrowed to the destination (Type)ofb upon assignment:
byte b = 0x62; // 0x62
b &= 0x0F; // 0x62 & 0x0F => 0x00000002 (now an int)
// 0x02 (cast back to a byte)
Example:
using System;
public class CompoundLogical {
public static void Main(string[] args) {
bool t, b, f = false;
t=b=true;
Console.WriteLine( (t & t) +" "+ (t & f) +" "+ (f & t) +" "+
(f&f));
Console.WriteLine( (t | t) +" "+ (t | f) +" "+ (f | t) +" "+
(f|f));

×