Behind the Scenes Look at C#: Operators

Have you ever wanted to gain an indepth knowledge of C# operators? This article, the first in a series, gets you off to a good start. It covers arithmetic operators (including unary arithmetic operators), relational operators, logical operators, assignment operators, the ternary operator, and operator precedence.

Contributed by
Rating: 4 stars4 stars4 stars4 stars4 stars / 33
June 29, 2005
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

The phrase "programming language operators" comes from the fact that operators are symbols and characters (as we will see later) that have been defined to perform an operation. I want make a note at this point before we go further that, to the runtime, there's no existence for operators, because the C# compiler generates method calls instead of using operators. For now, think of the expression x + y in C# as "int Add(x,y)" in the MSIL. That's why I will call x and y arguments to the operator, because those are in fact method arguments. Some of you would call them operands; that term is fine, too.

When using operators, there must be a return value of the performed operation (which is much more like a return value of a method call). The operator arguments may be singular; in this case, we will call the operator a unary operator. You may be dealing with two arguments, in which case they would be called binary operators, and new to C# is the ternary operator, which takes three arguments (?:).

Also note that operators are defined on the basis of type, so the .NET Framework permits us to write something like result = x + y; (where all these variables are primitive types), but you can't assume that Employee = Employee + Employee (where Employee is a user defined class). You need to overload the plus operator in order for this statement to work. Operator overloading will be discussed in detail in the second part of this article series.

Most C# operators are overloaded to work with primitive data types such as byte, integer, single, double and decimal. For the string class, C# overloads the += assignment operator and the + operator, as we will see. Also, you can assign objects to references by using the = assignment operator (the System.Object overloads the = operator). As a consequence of overloading the assignment operator (=) on the object class, overloading the == and != operators is a must for the object class, too.

We will discuss the various categories of C# operators, including arithmetic operators, relational operators, logical operators, and assignment, conditional and type Operators. We'll be throwing a lot of symbols around, so let's begin to discuss C# operators categories by the type of operations they perform on their arguments.

Arithmetic Operators

Like all programming languages, C# supports the basic arithmetic operators: the addition operator (+), multiplication operator (*), subtraction operator (-) and the division operator(/), plus the module operator (%). C# also supports the increment and decrement operators (++ and --). Let's take a look at examples for using these operators. Copy the following code and compile it:

using System;
namespace Operators
{
class Class1
{
static void Main(string[] args)
{
int x = 10;
int y = 5;
int 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);

result = x / y;
Console.WriteLine("x / y = {0}", result);

Console.ReadLine();
}
}
}

You will get the following result in the console window:

The add operator (+) takes two arguments and returns their sum. Note that when you use two different primitive types for the arguments, the C# compiler tries to convert one of the arguments' data types to ensure the integrity of the operation. For example, take a look at the following expression:

double x = 9 + 8.5;

The result is 17.5, as you expected -- but what happened is that the C# compiler implicitly converted (we will discuss type conversion after we finish C# operators) the 9 to 9.00 so that the expression could evaluate and produce the value. The same rules apply for the other basic arithmetic operators (*, - and /).

You can write the Main method as follows, too:

static void Main(string[] args)
{
int x = 10;
int y = 5;
int result;

Console.WriteLine("x + y = {0}", x + y);

Console.WriteLine("x - y = {0}", x - y);

Console.WriteLine("x * y = {0}", x * y);

Console.WriteLine("x / y = {0}", x / y);

Console.ReadLine();
}

And it will produce the same value, here we just passed the expression as the method argument so it will be evaluated and printed to the console window. Otherwise, the value would be stored in the result variable and then used it as an argument.

Modify the Main method as follows:

static void Main(string[] args)
{
int x = 10;
int y = 4;

Console.WriteLine("x / y = {0}", x / y);

Console.ReadLine();
}

You may expect that the result of the expression x / y is 2.5, and in fact it is, but the C# compiler will assume that the return type of the expression int / int is int, too, and the result will be 2 (not 2.5). The C# compiler will make an implicit conversion on the result. The solution of this problem is to declare the variables as double:

static void Main(string[] args)
{
double x = 10;
double y = 4;
double result = x / y;
Console.WriteLine("x / y = {0}", result);

Console.ReadLine();
}

The result then will be 2.5, as expected.

We can use the module operator (%) to get the remainder of the division of two numbers. For instance, with the same example as above, if we replaced the division operator with the module operator we would have the value 2:

static void Main(string[] args)
{
double x = 10;
double y = 4;
double result = x % y;
Console.WriteLine("x % y = {0}", result);

Console.ReadLine();
}

10 / 4 is equal to 2.5. We said that the module operator returns the remainder of the division operation, which in our case is 0.5, which gives us 2. You may recall from reading the article "Branching and Looping in C#, Part 1" when we used the module operator to test if the input number is an even or an odd number:

int x = Convert.ToInt32(Console.ReadLine());
if(x % 2 == 0)
{
Console.WriteLine("this is an EVEN number");
}
else
{
Console.WriteLine("this is an ODD number");
}

If x Module 2 is equal to 0, this means that it's an even number; if it's not 0 (we have a remainder in this case) then it's an odd number. This is a common use of the module operator, and in many scenarios you will find it a reliable method to construct your algorithms.

The increment and the decrement unary operators (++ and --) need a little discussion because they have two versions, the postfix and prefix versions. Before we explain how these operators work, copy the following code and compile it:

using System;
namespace Operators
{
class Class1
{
static void Main(string[] args)
{
int x = 5;

Console.WriteLine("x = {0}", x);
Console.WriteLine("++x value = {0}", ++x);
Console.WriteLine("x = {0}", x);
x = 5;
Console.WriteLine("x++ value = {0}", x++);
Console.WriteLine("x = {0}", x);
Console.ReadLine();
}
}
}

If this is the first time you have encountered these operators, you will be surprised at the result:

We have 5 assigned to x, then we execute the expression ++x, which increases the value of x by 1. We use this new value in the current expression, and we again print the value of x, which is 6. Again we reassign 5 to x and execute the expression x++, which does nothing at all in the current statement -- that's why x maintains the value of 5 in the current expression. It does its job in the next expression, however, where it increases the value of x by 1.

Put simply, the pre-increment operator (++x) increases the value of x by 1 in the current expression, and also uses this new value in the current expression. The post-increment operator (x++) will not increase the value of x in the current expression (it will use the current value of x) but it will increase x by 1 in the next statement. The pre-decrement operator (--x) decrements the value of x by 1 in the current expression, and use this new value in the current expression. The post-decrement operator (x--) maintains the value of x in the current expression and then increases it by 1 in the next statement.

Let's look at the MSIL code of the above application:

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 99 (0x63)
.maxstack 4
.locals init (int32 V_0)
IL_0000: ldc.i4.5
IL_0001: stloc.0
IL_0002: ldstr "x = {0}"
IL_0007: ldloc.0
IL_0008: box [mscorlib]System.Int32
IL_000d: call void [mscorlib]System.Console::WriteLine(string, object)
IL_0012: ldstr "++x value = {0}"
IL_0017: ldloc.0
IL_0018: ldc.i4.1
IL_0019: add
IL_001a: dup
IL_001b: stloc.0
IL_001c: box [mscorlib]System.Int32
IL_0021: call void [mscorlib]System.Console::WriteLine(string, object)
IL_0026: ldstr "x = {0}"
IL_002b: ldloc.0
IL_002c: box [mscorlib]System.Int32
IL_0031: call void [mscorlib]System.Console::WriteLine(string, object)
IL_0036: ldc.i4.5
IL_0037: stloc.0
IL_0038: ldstr "x++ value = {0}"
IL_003d: ldloc.0
IL_003e: dup
IL_003f: ldc.i4.1
IL_0040: add
IL_0041: stloc.0
IL_0042: box [mscorlib]System.Int32
IL_0047: call void [mscorlib]System.Console::WriteLine(string, object)
IL_004c: ldstr "x = {0}"
IL_0051: ldloc.0
IL_0052: box [mscorlib]System.Int32
IL_0057: call void [mscorlib]System.Console::WriteLine(string, object)
IL_005c: call string [mscorlib]System.Console::ReadLine()
IL_0061: pop
IL_0062: ret
} // end of method Class1::Main

There's much to explain here, but it would take an article of its own, so I will be brief and discuss only the difference between the pre-increment and post-increment operators. What we note from the above MSIL code is when the new value of x is produced. For the pre-increment operator, the add opcode is called before the value of x is placed on the stack, which increases the value by 1, and the new value 6 is ready for us to use in the current expression. For the post-increment operator, the add opcode is called after the value has been placed on the stack, which is 5, then it will be increased by 1 and ready to use for the next expression.

The Unary Arithmetic Operators

Yes, there are two more arithmetic operators, but they are unary operators, not binary like the above operators. As we have seen, binary Operators work on two arguments, much like a method that has two parameters. The unary operators work on one argument only; it's very much like a method that has only one parameter. C# defines two unary arithmetic operators, the minus operator (-) and the plus operator (+). As usual, let's begin with an example:

using System;
namespace Operators
{
class Class1
{
static void Main(string[] args)
{
int x = -10;
int y = +10;
int z = +-10;
int original = 3;
int result;
Console.WriteLine("x = {0}, y = {1}, z = {2}",x,y,z);

z = -10;
result = z * original;
Console.WriteLine("result = {0}", result);
result = z * +original;
Console.WriteLine("result = {0}", result);
Console.ReadLine();
}
}
}

 
The result will be as follows:

The minus operator, when associated with a variable (or a value) makes it a negative value to the C# compiler. The plus operator does nothing to the variable, so the variable is displayed in its original value -- which may be negative, as in our example.

Note the z variable, which contains the value +-10. This value actually is the same as -10, because if we say that we add nothing (+) to the value -10, it's still -10 with no modifications. The expression result = z * original; equal to 10 and the expression result = z * +original; is also equal to 10 because of that.

Relational Operators

Relational operators are those operators that compare two operands and return a Boolean value indicating the relationship between them. We have six relational operators: the less than operator (<), the greater than operator (>), the greater than or equal (>=), the less than or equal (<=), the equal operator (==) and the not equal operator (!=). Don't confuse the equal operator with the assignment operator (=). In C# you can't write code like the following:

bool z = x = y;

In C++ you can, but the C# compiler will issue an error. The relational operators work exactly as you expect with the primitive types. Let's take a look at an example:

using System;
namespace Operators
{
class Class1
{
static void Main(string[] args)
{
int x = 10;
int y = 4;
bool 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);
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);
Console.ReadLine();
}
}
}

 
The result that will be printed to the console window is:

Exactly as we expected, x greater than y is equal to true, and so on, but what if we need to use the relational operators with objects? Let's see an example:

using System;
namespace Operators
{
class Class1
{
static void Main(string[] args)
{
Employee MichaelYoussef = new Employee();
MichaelYoussef.Age = 22;
Employee SteveAnderson = new Employee();
SteveAnderson.Age = 22;

Console.WriteLine("Michael == Steven? = {0}",
MichaelYoussef == SteveAnderson);
Console.ReadLine();
}
}

class Employee
{
public int Age;
}
}

 
Although both Michael and Steve are 22 years old, you will get the following result to the console window:

With objects, equality is different from value-types, because the equal operator tests the value itself when used with Value-Types. It tests for REFERENCES when used with objects. We have false in the above code because both MichaelYoussef and SteveAnderson refer to different objects on the heap, although the value of the age field is the same in both the objects. We will learn how to handle this issue in the last article of the series, titled "C# Objects Manipulation."

Logical Operators

C# has eight logical operators, which form logical expressions. Logical expressions are used with control structure statements to control the execution of your application's code. Logical expressions work on Boolean Arguments and produce Boolean value that will be used by the control structure statements like the if statement. C# logical operators include: the NOT operator (!), the XOR (^) or the Exclusive OR Operator, the Short Circuit And Operator (&&), the AND Operator (&), the Short Circuit OR Operator (||) and the OR Operator (|). Let's take a look at an example that use all of these operators.

using System;
namespace Operators
{
class Class1
{
static void Main(string[] args)
{
int x = 10;
int y = 5;
bool result;
bool another;

// using the NOT Operator
Console.WriteLine("Using the ! Operator");
result = true;
Console.WriteLine("result before using ! equal to = {0}", result);
result = !result;
Console.WriteLine("result after using ! equal to = {0}", result);
Console.WriteLine();
Console.WriteLine("----------");
// using the XOR Operator
Console.WriteLine("using the ^ Operator");
result = true;
another = true;
Console.WriteLine("using the ^ with 2 true arguments");
Console.WriteLine("result ^ another equals to {0}", result ^ another);

Console.WriteLine("using the ^ with 2 false arguments");
result = false;
another = false;
Console.WriteLine("result ^ another equals to {0}", result ^ another);

Console.WriteLine("using the ^ with 1 true and another false arguments");
result = true;
another = false;
Console.WriteLine("result ^ another equals to {0}", result ^ another);

// using the && operator
Console.WriteLine();
Console.WriteLine("----------");
result = true;
if(result && ReturnTrue())
{
Console.WriteLine("using the short circuit and (&&)"
+ " the ReturnTrue() method will be called only if the"
+ " result is true");
}
Console.WriteLine();
Console.WriteLine("setting result to false");
result = false;
if(result && ReturnTrue())
{
Console.WriteLine("Do you see this line?");
}
Console.WriteLine("although that ReturnTrue() returns true it will not called" +
" because result is false and the if block will not execute");

// using the || operator
Console.WriteLine();
Console.WriteLine("---------");
Console.WriteLine("using the || operator");
Console.WriteLine("setting result to true");
result = true;
if(result || ReturnTrue())
{
Console.WriteLine("ReturnTrue() will not be called because" +
" result = true");
}

Console.WriteLine("setting result to false and use the || again");
result = false;
if(result || ReturnTrue())
{
Console.WriteLine("ReturnTrue() is called because"
+ " result = false");
}

Console.WriteLine();
Console.WriteLine("-----------");
// using the full evaluation and operator &
Console.WriteLine("setting result to true");
result = true;
Console.WriteLine("using the full evaluation and operator &");
if(result & ReturnTrue())
{
Console.WriteLine("ReturnTrue() is called if result is true or false");
}
Console.WriteLine("-----------");
Console.WriteLine("setting result to false");
result = false;
Console.WriteLine("using the full evaluation and operator &");
if(result & ReturnTrue())
{
Console.WriteLine("ReturnTrue() is called if result is true or false");
}

Console.ReadLine();
}

static bool ReturnTrue()
{
Console.WriteLine("Inside the ReturnTrue method now");
return true;
}
}
}

Yes it's a lot of code, but it's simple. The result that will be displayed in the console window will look like this:

What happened? We have used some integer variables and some other Boolean variables in order to test the functionality that these operators offer us. The NOT operator just inverts the Boolean value of the variable; we have tested it with the result variable.

The Exclusive OR Operator (^) as its name implies, is exclusive, which means that it will evaluate to true if only one of the two arguments is true. If both arguments are true it will evaluate to false, and if both arguments are false it will evaluate to false too.

The Short Circuit And Operator (&&) is familiar to C++ developers (as is the Short Circuit Or ||). The Short Circuit And operator evaluates the second argument only if the first argument is true. If the first argument is false (this means that the expression will be evaluated to false, because with the And Operator both arguments must evaluates to true) it will not evaluate the second expression. The Short Circuit Or Operator (||) is similar, it will short circuit when the first argument evaluates to true. In other words, there's no need to evaluate the second expression, because with the OR Operator it will evaluate to true when one expression evaluates to true. And the above example illustrate this mechanism.

The And (&) and Or (|) Operators are called full evaluation operators because they evaluate both of the expressions whether the first expression evaluates to true or false. Sometimes you need this behavior. In the above example, if(result & ReturnTrue()) you need the call to the method ReturnTrue() whether the first expression evaluated to true or false.

Assignment Operators

You have seen the first assignment operator (=) and we have used it all over our code examples to assign a value to a variable. The assignment operators have two arguments, the left argument and the right argument ( for example x = 5;). Note that this statement only puts the value 5 in the x variable, but there is another way to assign values like this one (x = y;). In this case you copy the right value (of the y variable) to the left value (into the x variable). 

This is the most basic assignment process. It does makes sense that the left value is a physical memory location, so it's a variable (or indexer) and the right value is the value that will be copied to the left value, so it may be a constant value (5), an expression (x + 4), a variable (x) or even a method call that returns a value. Thus, you can't write a statement such as 15 = 10, you must write it in the form x = 10. The assignment operation proceeds from the right to left because it gets the value on the right and copies it to the variable on the left.

C# has many assignment operators other than the simple = operator. There's the addition assignment operator (+=), the subtraction assignment operator (-=), the multiplication assignment operator (*=), the division assignment operator (/=) and the module assignment operator (%=), plus other bitwise assignment operators, which I will discuss with the bitwise operators. For now I will discuss the above operators. Copy the following code into a .cs file, compile it, then run the application.

using System;
namespace Operators
{
class Class1
{
static void Main(string[] args)
{
int x = 5;
int y = 5;

x = x + y;
Console.WriteLine("y assigned to x and x = {0}",x + y);
x += y;
Console.WriteLine("Using the += operator x = {0}", x);

Console.WriteLine("**********");

x = x - y;
Console.WriteLine("x = x - y and x = {0}",x - y);
x -= y;
Console.WriteLine("Using the -= operator x = {0}", x);

Console.WriteLine("**********");

x = x * y;
Console.WriteLine("x = x * y and x = {0}",x * y);
x *= y;
Console.WriteLine("Using the *= operator x = {0}", x);

Console.WriteLine("**********");

x = x / y;
Console.WriteLine("x = x / y and x = {0}",x / y);
x /= y;
Console.WriteLine("Using the /= operator x = {0}", x);

Console.WriteLine("**********");

x = x % y;
Console.WriteLine("x = x % y and x = {0}",x % y);
x %= y;
Console.WriteLine("Using the %= operator x = {0}", x);
Console.ReadLine();
}
}
}

The result is:

The complex assignment operators don't just copy the right value into the left value; it's a little more complicated than that. For example, the += operator takes the value of the right side and adds it to the left side. It's the same as coding x = x + y, but the C# compiler doesn't process it that way because it knows exactly what the += operator does. To understand how these operators work, I will explain it using x = x operator y expression.

The Ternary Operator

There's only one ternary operator in C#, the (?:) ternary operator. It has three arguments. This operator is very useful in writing elegant C# code because its first argument takes a Boolean expression, and if it's evaluated to true, the second argument executes; if it's evaluated to false, the third argument executes. Consider the following if statement:

static void Main(string[] args)
{
int x = 5;
if(x == 5)
{
Console.WriteLine("x equal to 5");
}
else
{
Console.WriteLine("x not equal to 5");
}
}

This code prints to the console "x equal to 5" but we can use the ternary operator to write more concise code, as follows:

int x = 5;
Console.WriteLine(x == 5? "x equal to 5" : "x not equal to 5");

You will get the same result to the console window and as you can see, only one line of code is needed.

Operator Precedence

It's very common to have more than one operator in your expressions. For example, here is an expression with several operators: 2 + 3 * 4. What's the result of this expression? If we add 2 and 3 then multiply by 4, the product will be 20. If we multiply 3 by 4 and then add 2 the product will be 14. Which one is true? Logically both of them are true because 2 + 3 = 5 multiplied by 4 = 20 and 3 multipled by 4 = 12 added to 2 = 14. So we have two operators in the expression, but we need a way to tell which one will be evaluated first. There are two procedures for doing this. The first way is to use parentheses () to tell the C# compiler that you want to evaluate the enclosed expression first, as in the following code example:

namespace Operators
{
class Class1
{
static void Main(string[] args)
{
Console.WriteLine((2 + 3) * 4);
Console.WriteLine(2 + (3 * 4));
Console.ReadLine();
}
}
}

The result in the console window will be:

Our problem has been solved with the parentheses. The parentheses just determine the order of evaluation for the operators in the expression, so the enclosed expression evaluates first and then the outer expression. So for this example, (2 + 3) = 5 then multiplied by 4 = 20 because the compiler evaluates the enclosed expression first and multiplies the result.

The process of the order of evaluation of operators is called operators precedence. If you don't want to use the parentheses, and would rather rely on the second procedure, it is the default C# operator precedence. The C# compiler evaluates operators based on the following table:

The IntelliSense Operator .

The Parentheses Operator ()

Array Index Operator []
The Post Increment Operator ++
The Post Decrement Operator --
The new Operator
The typeof Operator
The checked Operator
the unchecked Operator
The unary plus +
The unary minus -
the unary !
The unary ~
The Pre Increment Operator ++
The Pre Decrement Operator --
The multiplication Operator *
The division Operator /
The Module Operator %
The Addition Operator +
The Subtraction Operator -
The Shift-Left Operator <<
The Shift-Right Operator >>
The Less Than Operator <
The Less Than or Equal Operator <=
The Greater Than Operator >
The Greater Than or Equal Operator >=
The is Operator
The Equality Operator ==
The Is Not Equal Operator !=
The And Operator &
The XOR Operator ^
The Or Operator |
The Short-Circuit And Operator &&
The Short-Circuit Or Operator ||
The Ternary Operator ?:
The Assignment Operators as following

=,*=,/=,+=,-=,<<=,>>=,&=,^= and |=

Using this table you can tell that the C# compiler will do the following:

  1. Multiply 4 by 3 because the * operator has a higher precedence than the + operator (the operator precedence table lists the C# operators from the highest to lowest precedence).

  2. Add the product to 2, which equals 14, and that's all.

In the next article we will examine the concepts behind operator overloading.

blog comments powered by Disqus
C# ARTICLES

- Beginning C#
- ASP.NET RedirectPermanent Method using C# an...
- C Programming Language and UNIX Pioneer Pass...
- Using Facebook JavaScript SDK in ASP.NET wit...
- ASP.NET Export to Excel and Word using VB.NE...
- WAV and MP3 Streaming with ASP.Net and C#
- Game Programming using SDL: the File I/O API
- C# and Java Developer Jobs on the Rise
- The Future Evolution of C# and VB.NET
- C# If and Else-if Statements
- How To Use the C# String Replace Method
- 5 Ways to Parse XML in C#
- C# Meets Design Patterns
- Coding a CRC-Generating Algorithm in C
- Cyclic Redundancy Check

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 3 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials