Type Casting or Type Conversion is a mechanism to convert one data type value to another one. Type conversion is possible if both the data types are compatible to each other; otherwise you will get an InvalidCastException.
Implicit conversion is being done automatically by the compiler and no data will be lost. It includes conversion of a smaller data type to a larger data types and conversion of derived classes to base class. This is a safe type conversion.
int smallnum = 654667; // Implicit conversion long bigNum = smallnum;
class Base
{
public int num1 { get; set; }
}
class Derived : Base
{
public int num2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
Derived d = new Derived();
//Implicit Conversion
Base b = d;
}
}
Explicit conversion is being done by using a cast operator. It includes conversion of larger data type to smaller data type and conversion of base class to derived classes. In this conversion information might be lost or conversion might not be succeed for some reasons. This is an un-safe type conversion.
long bigNum = 654667; // Explicit conversion int smallnum = (int)bigNum;
class Base
{
public int num1 { get; set; }
}
class Derived : Base
{
public int num2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
Base b = new Base();
//Explicit Conversion
Derived d = (Derived)b;
}
}
User-defined conversion is performed by using special methods that you can define to enable explicit and implicit conversions. It includes conversion of class to struct or basic data type and struct to class or basic data type. Also, all conversions methods must be declared as static.
class RationalNumber
{
int numerator;
int denominator;
public RationalNumber(int num, int den)
{
numerator = num;
denominator = den;
}
public static implicit operator RationalNumber(int i)
{
// Rational Number equivalant of an int type has 1 as denominator
RationalNumber rationalnum = new RationalNumber(i, 1);
return rationalnum;
}
public static explicit operator float(RationalNumber r)
{
float result = ((float)r.numerator) / r.denominator;
return result;
}
}
class Program
{
static void Main(string[] args)
{
// Implicit Conversion from int to rational number
RationalNumber rational1 = 23;
//Explicit Conversion from rational number to float
RationalNumber rational2 = new RationalNumber(3, 2);
float d = (float)rational2;
}
}
There are two more casting terms Upcasting and Downcasting. basically these are parts of Implicit conversion and Explicit conversion.
Implicit conversion of derived classes to base class is called Upcasting and Explicit conversion of base class to derived classes is called Downcasting.
class Base
{
public int num1 { get; set; }
}
class Derived : Base
{
public int num2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
Derived d1 = new Derived();
//Upcasting
Base b1 = d1;
Base b2 = new Base();
//Downcasting
Derived d2 = (Derived)b2;
}
}
Implicit conversion of a value type (int, char etc.) to a reference type (object), is known as Boxing. In boxing process, a value type is being allocated on the heap rather than the stack.
Explicit conversion of same reference type (which is being created by boxing process); back to a value type is known as unboxing. In unboxing process, boxed value type is unboxed from the heap and assigned to a value type which is being allocated on the stack.
// int (value type) is created on the Stack int stackVar = 12; // Boxing = int is created on the Heap (reference type) object boxedVar = stackVar; // Unboxing = boxed int is unboxed from the heap and assigned to an int stack variable int unBoxed = (int)boxedVar;
int i = 10; ArrayList arrlst = new ArrayList(); //ArrayList contains object type value //So, int i is being created on heap arrlst.Add(i); // Boxing occurs automatically int j = (int)arrlst[0]; // Unboxing occurs
Sometimes boxing is necessary, but you should avoided it if possible, since it will slow down the performance and increase memory requirements.
For example, when a value type is boxed, a new reference type is created and the value is copied from the value type to the newly created reference type. This process takes time and required extra memory (around twice the memory of the original value type).
Attempting to unbox a null causes a NullReferenceException.
int? stackVar = null; // Boxing= Integer is created on the Heap object boxedVar = stackVar; // NullReferenceException int unBoxed = (int)boxedVar; //Object reference not set to an instance of an object.
Attempting to unbox a reference to an incompatible value type causes an InvalidCastException.
int stackVar = 12; // Boxing= Integer is created on the Heap object boxedVar = stackVar; // InvalidCastException float unBoxed = (float)boxedVar; //Specified cast is not valid.
A C# program is expressed in statements. A statement is a single line of code that ends with a semicolon or a block of multiple single-line statements enclosed in {} brackets. A statement block can have nested blocks.
Decision making statements helps you to make decision based on certain conditions. These conditions are specified by a set of decision making statements having boolean expressions which are evaluated to a boolean value true or false. There are following types of decision making statements in C#.
An if statement consists of a boolean expression which is evaluated to a boolean value. If the value is true, the if block is executed otherwise next statement(s) would be executed.
You can have multiple if statement as shown below-
public class Example
{
static void Main()
{
int a = 5, b = 2;
int result = a / b;
if (result == 2)
{
Console.WriteLine("Result is 2");
}
if (result == 3)
{
Console.WriteLine("Result is 3");
}
}
}
/* Output
Result is 2
*/
You can also do nesting of if statement means an if statement inside another if that is called nested if statement.
An if-else statement consists of two statements – if statement and else statement. When the expression in an if-statement is evaluated to true, the if block is executed otherwise the else block would be executed.
public class Example
{
static void Main()
{
int a = 5, b = 6;
int result = a - b;
if (result > 0)
{
Console.WriteLine("Result is greater than zero");
}
else
{
Console.WriteLine("Result is smaller than or equal to zero");
}
}
}
/* Output
Result is smaller than or equal to zero
*/
The If-Else-If ladder is a set of statements that is used to test a series of conditions. If the first if statement met the result, the code within the if block executes. If not, control passes to the else statement, which contains a second "if" statement. If second one met the result, code within the if block executes. This continues as a series of else if statements. A default else code block may execute when no condition has been evaluated to true.
If-Else-If ladder must contain more specific case at the top and generalize case at the bottom.
public class Example
{
static void Main(string[] args)
{
char grade = 'B';
if (grade == 'A')
{
Console.WriteLine("Excellent!");
}
else if (grade == 'B')
{
Console.WriteLine("Well done");
}
else if (grade == 'D')
{
Console.WriteLine("You passed");
}
else if (grade == 'F')
{
Console.WriteLine("Better try again");
}
else
{
Console.WriteLine("You Failed!");
}
}
}
/* Output
Well done
*/
Switch statement acts as a substitute for long If-Else-If ladder that is used to test a series of conditions. A switch statement contains one or more case labels which are tested against the switch expression.
When one case matches the value with the result of switch expression, the control continues executing the code from that label. When no case label contains a matching value, control is transferred to the default section, if it exists. If there is no default section, no action is taken and control is transferred outside the switch statement.
public class Example
{
static void Main(string[] args)
{
char grade = 'B';
switch (grade)
{
case 'A':
Console.WriteLine("Excellent!");
break;
case 'B':
case 'C':
Console.WriteLine("Well done");
break;
case 'D':
Console.WriteLine("You passed");
break;
case 'F':
Console.WriteLine("Better try again");
break;
default:
Console.WriteLine("You Failed!");
break;
}
}
}
/* Output
Well done
*/
Each case label specifies a constant value.
A switch statement can have multiple switch sections, and each section can have one or more case labels.
Unlike C and C++, C# does not allow continuing execution from one switch section to the next. It means each switch section must be separated by a break or other jump statement such as goto, return and throw.
Unlike If-Else-If ladder, it is not mandatory to put more specific case at the top and generalize case at the bottom since all the switch cases have equal precedence.
Typically, a switch statement is faster than equivalent if-else-if statement. This is due to the compiler's ability to optimise the switch statement. In case of a if-else-if ladder, the compiler need to check each and every if condition in order to execute. While in case of a switch statement compiler does not need to check earlier cases, the compiler is able find out the matching case which leads the fast execution.
The break, got, continue, return and throw statements are known as jump statements. These are used to transfer program control from one point in the program to another point, at any time.
This statement terminates the execution of loop or switch in which it appears and transfers program control to the next statement which is placed immediately after the loop or switch.
public class Example
{
static void Main(string[] args)
{
for (int i = 1; i <= 10; i++)
{
if (i == 5)
{
break;
}
Console.WriteLine(i);
}
Console.WriteLine("Next statement placed after loop");
}
}
/* Output:
1
2
3
4
Next statement placed after loop
This statement is also used to terminates an inner nested loop, and return control to the outer loop.
This statement transfers program control to a labeled statement. The label statement must exist in the scope of the goto statement. More than one goto statement can transfer control to the same label. This statement can be used to get out from a loop or an inner nested loop to outer loop.
public class Example
{
static void Main(string[] args)
{
for (int i = 1; i <= 10; i++)
{
if (i == 5)
{
goto Exitlabel;
}
Console.WriteLine(i);
}
Console.WriteLine("Next statement placed after loop");
Exitlabel: //goto label
Console.WriteLine("Labeled statement");
}
}
/* Output:
1
2
3
4
Labeled statement
*/
Unlike break statement, it does not transfer the program control to next statement which is placed immediately after the loop or switch.
You can also use goto statement to transfer control to a specific switch-case label or the default label in a switch statement.
It is not recommended to use goto statement since this makes the program logic complex and difficult to understand. It also becomes difficult to trace the control flow of a program execution.
This statement skips the current iteration and passes program control to the next iteration of the enclosing loop in which it appears.
public class Example
{
static void Main(string[] args)
{
for (int i = 1; i <= 10; i++)
{
if (i <= 5)
{
continue;
}
Console.WriteLine(i);
}
Console.WriteLine("Next statement placed after loop");
}
}
/* Output:
6
7
8
9
10
Next statement placed after loop
*/
Unlike break statement, it does not terminates the loop execution but it skip the current iteration of the loop and passes program control to the next iteration of the enclosing loop.
This statement terminates the execution of the method in which it appears and returns control to the calling method.
public class Example
{
static void Main(string[] args)
{
double length = 5.0, width = 2.5;
double result = CalculateArea(length, width);
Console.WriteLine("The area is {0:0.00}", result);
}
public static double CalculateArea(double length, double width)
{
double area = length * width;
return area;
}
}
/* Output:
The area is 12.50
*/
If the return statement appear in a try block and the finally block is also exists, it finally block will be executed before control returns to the calling method.
This statement throws an exception which indicate that an error has occurred during the program execution. This statement is used with a combination of try-catch or try-finally statements.
public class Example
{
static void Main(string[] args)
{
try
{
int number = 5, x = 0;
double result = number / x;
Console.WriteLine("Result is {0}", result);
}
catch (Exception ex)
{
Console.WriteLine("Exception: "+ex.Message);
}
}
}
/* Output:
Exception: Attempted to divide by zero.
*/
There are 3 types of comments in C#.
Single line(//)
Multi(/* */)
Page/XML Comments(///).
There are 3 types of comments in C#.
Single line(//)
Multi(/* */)
Page/XML Comments(///).
There are 3 types of comments in C#.
Single line(//)
Multi(/* */)
Page/XML Comments(///).