Page 1 of 1

C# Basic Operators

#1 Curtis Rutland  Icon User is online

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4559
  • View blog
  • Posts: 7,972
  • Joined: 08-June 10

Posted 21 March 2011 - 03:29 PM

*
POPULAR

Learning C# Series
Operators

So, you've written your first program, and you've learned about the basic types in .NET. Now you need to learn how to do things with those types.

The most basic way that types interact is through operators. This tutorial will walk you through some of the more basic.

Why is this important to learn about?

Again, operators are the most basic way that you can create interactions between objects/values. How could you ever do math without knowing what plus, minus, times, and divide do? Well, those are mathematical operators. The same principles apply to programming operators: without them, you'll probably never get anything done.

Definitions of terms used.


Note: All examples were created using Visual Studio 2010, targetting the .NET Framework 4.0. We'll do our best to point out anything that might not work in older versions.

Operators

If you followed the link in the definitions above, you'll see that C# has quite a few operators. Some are single character, some are multiple. Some are unary, some are binary; one is even ternary (one of my favorites, actually).

Thes operators, just like in mathematics, follow an order of operations. The MSDN list of C# operators lists them in groups of precedent. Operators in the same group are evaluated left-to-right.

Parenthesis ( )

Parenthesis have several functions. First and foremost, they're used for order-of-operations, just like in math. 5 + 1 * 3 equals 8, but (5 + 1) * 3 equals 18. It works the same way in C#. Operations inside of parenthesis are evaluated before those outside of them. Parenthesis are also used to invoke methods (we'll cover methods in another tutorial later), and for casting operations. Casting will also be covered later, but in breif: it's a way to convert one type to another.

Here's an example of casting:
int x = (int)3.141;


In that example, we're taking a double, and converting it into an integer. You can't cast any type to any other: cast operations must either be performed on classes that are related via inheritance, or be defined (using implicit or explicit) in the class definition. But that's out of scope of this tutorial.

Unary Operators

Unary operators take only one operand. A mathematical example would be the Factorial operator.

Increment (++) and Decrement (--)
If you've ever heard of C++, this is where the ++ comes from. ++ increments the the value it's applied to. This operator can be either postfix (x++;) or prefix (++x;). In either case, after the expression is evaluated, x will be one greater than it was before. These operators can only be applied to numeric types by default.

Now, there's a reason why you can use these operators either way, and it's quite important. Before I explain, consider this code:

int a = 0;
int b = 0;
Console.WriteLine(++a);
Console.WriteLine(b++);



As explained earlier, both a and b will have a value of 1 after this code is evaluated. However, if you've tried this yourself, you've noticed that the output doesn't match!

Output

Quote

1
0


Why, when both adds one to the variable? Because they evaluate at different times. ++a means "add one to the value of a, then return that value." b++ means "return the value of b, then add one to it". It's a very important distinction if you're not using it as a standalone operation. I suggest you get in the habit of using the prefix (++a) version unless you need the postfix behavior. This will cause less confusion down the road.

Note: the -- operator works exactly the same way, except decreasing the value by one instead of increasing.

Plus (+) and Minus (-) as Unary Operators
These operate the same way mathmatical positive and negative signs do. +x simply returns x. -x returns x * -1.

Boolean Negation (!)
The bang (or exclamation point) operator negates boolean types. !true returns false, and !false returns true. This is often useful to invert a boolean statement:

bool respondedNo = false;
while (!respondedNo) {
    Console.WriteLine("Continue?");
    respondedNo = Console.ReadKey().Key == ConsoleKey.N;
}


Binary Operators

Binary operators take two operands. These are the most familiar, since you've been using these since grade school.

Important note: None of these operators except for the assignment operators modify their operands. They return the result of their evaluation. So if you do a + b, after it's evaluated, both a and b will still have their original values. You must either use it in further evaluation or assign the result to a variable for it to have any significance.

Multiplicitive Operands (*, /, %)
These three share precedence in the order of operations, and as such, are evaluated left-to-right. First is the Multiply operator (*). This returns the product of the operands to the left and right. The Divide operator (/) behaves the same, except dividing the two operands.

Console.WriteLine(10 * 5);
Console.WriteLine(20 / 4);
;

Quote

50
5


If you use ints to do division, you may find unexpected results. For example:
Console.WriteLine(1 / 3);


Output

Quote

0


You'd expect the output to be 0.3333 repeating, but it's not. That's because integers can't possibly have decimal values, so the decimals are trimmed (not rounded! 0.999 becomes 0). By changing one of the operands to a float/double/decimal, the entire operation is evaluated as a double.

Console.WriteLine(1 / 3.0);

Quote

0.333333333333333



Note: Integer Division by zero will throw a DivideByZeroException. That's a bad thing, so don't do it. Dividing a floating-point number by zero will not result in an exception, but will return the value Double.NaN (Not a Number).

This naturally leads us to the Modulus operator (%). Remember in grade school when you started learning division? You didn't learn with decimals, but with integer quotients and remainders. The modulus operation returns the remainder of integer division. For example:

Console.WriteLine(20 % 6);

Quote

2


20 / 6 is equal to 3.33 repeating. However, using integer division, it is 3. 6 * 3 is equal to 18. 20 - 18 equals 2. In other words, 20 / 6 = 18 R 2. Modulus returns the remainder. This doesn't sound immediately useful, but it can be if you know a bit of math. For instance, we can use it to determine even numbers:

for (int i = 0; i < 10; i++) {
    if (i % 2 == 0)
        Console.WriteLine("{0} is even.", i);
    else
        Console.WriteLine("{0} is odd.", i);
}


Quote

0 is even.
1 is odd.
2 is even.
3 is odd.
4 is even.
5 is odd.
6 is even.
7 is odd.
8 is even.
9 is odd.


Additive Operators (+, -)
These both share a precedence, below that of the multiplicitive operators. Just like in actual mathematics. For numeric types, + and - do exactly what you think they do: return the result of adding or subtracting the operators respectively.

However, + has another function: string concatenation. Concatenation basically means joining together. Here's an example of concatenating strings:

string a = "Hello";
string b = "World";
string c = a + " " + b;
Console.WriteLine(c);


Quote

Hello World


Important note: Strings aren't numbers! There is a huge, huge difference between adding numbers and concatenating strings. Since strings can represent numbers though, it may look confusing. But remember, if it's a string, it'll be joined up, not added together.

Console.WriteLine(1 + 2);
Console.WriteLine("1" + "2");


Quote

3
12


Equality Operators (==, !=)
C# makes an important distinction that not all languages make: "Equality and Assignment are different things, therefore should use different operators." What that means is, there's a difference between saying "I want to assign the value of b to a," and "I want to know if a is equal to b."

To support that distinction, C# uses == as the comparison operator.

if(x == 1)
  //do something


In the preceeding example, we compare x to 1. The result will be either true or false, depending on if x is equal to 1.

Important note: The equality operator compares values for value types, but for most reference types, it checks to see if both operands are pointing to the same block of memory. This is a hugely important distinction, since two objects can be what you would consider equal, but in distinct memory, so the compiler won't consider them equal. You can define equality for reference types by overriding the .Equals method, which is outside the scope of this tutoria..

The != (not equals) operator is the exact opposite. It returns true when the operands are not equal, and false when they are.

Other Comparison Operators (&&,||)
These operators are all about boolean logic. If you've ever taken a logic class, you should have covered this. Basically, they're a way of expressing AND (&&) and OR (||). && has a higher precedence in order of operations than ||.

&& will return true if both of the operands are true. Otherwise it will return false.

|| will return true if one of the operands are true. Only if both are false will it return false.

To see this in action:

bool x = true;
bool y = false;

if (x && y)
    Console.WriteLine("Both were true.");
else
    Console.WriteLine("At least one was false.");

if (x || y)
    Console.WriteLine("At least one was true.");
else
    Console.WriteLine("Both were false.");



Quote

At least one was false.
At least one was true.


Note: There are also bitwise versions of these operators, (&, |), as well as a bitwise XOR (^). XOR returns true if one and only one of the operands are true, otherwise false. Against bools, the bitwise operators work exactly the same. However, they also operate against integral values as well. They compare each bit of the binary representation of the int, and return the result. It's not something you generally need to concern yourself with, and is outside the scope of this tutorial.

Assignment operators (=, +=, -=, *=, /=, %=)
As already discussed in the Equality Operators section, assignment and equality are different things. Assignment means "take the evaluated value on the right, and assign it into the variable on the left, then return that value if necessary" Of course, this means that there must be a variable on the left for this to be a valid expression. Some examples of assignment:

int x = 1; //assign 1 to x.
int y = x + 1; //evaluate x + 1, then assign the result (2) to y.


It's important to note that once an assignment is evaluated, it returns the value on the right as a result. This means that an assignment can be used in another assignment!

int x = 1;
int y;
int z = y = 2;


In this example, z is to be assigned the result of (y = 2). So the compiler evaluates y = 2. 2 is assigned to y, then 2 is returned. Now that y = 2 evaluated to 2, z is assigned 2.

This is convoluted and not generally used.

Now, there are several other operators mentioned (+=, -=, /=, *=, %=). Basically, these are the combination of assignment and arithmatic. For example: x += 5; is exactly the same as x = x + 5. See? A combination of assignment and arithmatic. This works the same for each of these operators, except with their own arithmatic operator (- for -=, * for *=, etc).

Ternary Operator

This is the only ternary operator in C#: the conditional operator (?:). Here's an example of the pattern it follows:

x = a ? b : c;


That is the equivalent of this:

if(a)
  x = b;
else
  x = c;


Therefore, a must evaluate to a bool, and b and c must evaluate to the same type as x.

A somewhat more practical example:
string longString = "abcdefghijklmnop";
string shortString = longString.Length > 5 ? longString.Substring(0, 5) : longString;


This says "if longString is longer than 5, assign the Substring of longString to shortString. Otherwise, just assign longString to shortString."

In Conclusion

This in no way covered every operator that C# includes. There are several that are rarely used, or are simply more advanced than the scope of this topic. You can see all of them here:

http://msdn.microsof...(v=VS.100).aspx

Each is a link that you can follow to see it in action.

Another note: when defining a class, operators can be overloaded. We'll cover this in a later tutorial, but I want you to be aware that this is possible. Overloading an operator means that it can do something other than it's default operation. For example, the minus (-) operator is overloaded on DateTime in two ways: if you subtract a TimeSpan from a DateTime, you'll get a new DateTime. If you subtract a DateTime from a DateTime, you'll get a TimeSpan. Example:

DateTime dt1 = new DateTime(2011, 3, 21);
//subtract a timespan of 5 days from dt1 to create dt2
DateTime dt2 = dt1 - TimeSpan.FromDays(5); 
//now, let's subtract dt2 from dt1 to get a timespan back
TimeSpan difference = dt1 - dt2;            



You don't need to understand how to do it at the moment, just the fact that some objects may have operators that behave differently than normal.

Hope you've enjoyed this installment of the C# Learning Series! Next one's coming soon!

See all the C# Learning Series tutorials here!

Is This A Good Question/Topic? 8
  • +

Replies To: C# Basic Operators

#2 bronze  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 38
  • Joined: 08-January 11

Posted 21 March 2011 - 04:38 PM

It's a great tutorial, you explain everything in a nice, new user-friendly way. Keep up the good work!
Was This Post Helpful? 0
  • +
  • -

#3 Curtis Rutland  Icon User is online

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4559
  • View blog
  • Posts: 7,972
  • Joined: 08-June 10

Posted 08 May 2013 - 10:08 AM

Quote

Note: There are also bitwise versions of these operators, (&, |), as well as a bitwise XOR (^). XOR returns true if one and only one of the operands are true, otherwise false. Against bools, the bitwise operators work exactly the same.


After re-reading this section, I want to make a small clarification: they behave similarly, but not identically.

The boolean AND/OR operators use what's called "Short-circuit evaluation". What this means is that if at any time during evaluation that there is enough information to determine the result of the expression, no further evaluation is done. Put more simply, if you can figure out the truth of a statement halfway through it, the second half isn't looked at at all.

It may seem like a minor distinction, but it can have have a real effect on the way you write code. Consider the following example:

static void Main()
{
    bool result = ArgumentA(true) || ArgumentB(false);
    Console.WriteLine("Press any key to continue...");
    Console.ReadKey();
}

private static bool ArgumentA(bool arg)
{
    Console.WriteLine("Entered ArgumentA method.");
    return arg;
}

private static bool ArgumentB(bool arg)
{
    Console.WriteLine("Entered ArgumentB method.");
    return arg;
}



What do you think the output is?

Quote

Entered ArgumentA method.
Press any key to continue...


You don't see the WriteLine for ArgumentB being called anywhere. Why? Well, as it turns out, when two operations have equal importance in the order of operations, they're evaluated from left-to-right. So, in this example, both the left and the right side have equal importance, so the left is evaluated first.

The left side returns true. Now, if we know our truth tables, we know that if either side of an OR statement is true, the entire statement is true. That means we don't care whether or not the right side is true or not, so we can skip it entirely.

This is a trivial example, but here's a snippet from an actual project I've written:

if(message == null || message.Text == null){
  //do error handling...


If both sides were always evaluated, then this code would crash when message is null, because you can't access the Text property on a null reference. But because we know it will never be evaluated if message is null, then we can safely put them in the same statement. It's also important when your expressions have side effects.

Now, back to the original point. This is where the bitwise operators differ. When you use the bitwise operators against boolean arguments, they do not use short-circuit evaluation.

Consider the slightly modified example:

static void Main()
{
    bool result = ArgumentA(true) | ArgumentB(false);
    Console.WriteLine("Press any key to continue...");
    Console.ReadKey();
}

private static bool ArgumentA(bool arg)
{
    Console.WriteLine("Entered ArgumentA method.");
    return arg;
}

private static bool ArgumentB(bool arg)
{
    Console.WriteLine("Entered ArgumentB method.");
    return arg;
}



Quote

Entered ArgumentA method.
Entered ArgumentB method.
Press any key to continue...


The result of the comparison is the same, but since both sides are evaluated, both side effects occur. So, if you ever need a comparison that requires both side effects to happen, use the bitwise operators.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1