Csharp
Csharp
C# was first introduced with .NET Framework 1.0 in the year 2002 and evolved much since then.
The following table lists important features introduced in each version of C#:
C# 3.0 .NET Framework 3.0\3.5 Visual Studio 2008 Implicitly typed local variables
Object and collection initializers
Auto-Implemented properties
Anonymous types
Extension methods
Query expressions
Lambda expressions
Expression trees
Partial Methods
C# 4.0 .NET Framework 4.0 Visual Studio 2010 Dynamic binding (late binding)
Named and optional arguments
Generic co- and contravariance
Embedded interop types
C# 6.0 .NET Framework 4.6 Visual Studio 2013/2015 Expression Bodied Methods
Auto-property initializer
nameof Expression
Primary constructor
Await in catch block
Exception Filter
String Interpolation
First C# Program
Here, you will learn to create a simple console application in C# and understand the basic building
blocks of a console application.
C# can be used in a window-based, web-based, or console application. To start with, we will create a
console application to work with C#.
Open Visual Studio (2017 or later) installed on your local machine. Click on File -> New Project...
from the top menu, as shown below.
From the New Project popup, shown below, select Visual C# in the left side panel and select the
Console App in the right-side panel.
Select Visual C# Console App Template
In the name section, give any appropriate project name, a location where you want to create all the
project files, and the name of the project solution.
Click OK to create the console project. Program.cs will be created as default a C# file in Visual
Studio where you can write your C# code in Program class, as shown below. (The .cs is a file
extension for C# file.)
C# Console Program
Every console application starts from the Main() method of the Program class. The following
example displays "Hello World!!" on the console.
namespace CSharpTutorials
{
class Program
{
static void Main(string[] args)
{
string message = "Hello World!!";
Console.WriteLine(message);
}
}
}
Try it
The following image illustrates the important parts of the above example.
C# Code Structure
1. Every .NET application takes the reference of the necessary .NET framework namespaces that it
is planning to use with the using keyword, e.g., using System.Text.
2. Declare the namespace for the current class using the namespace keyword, e.g., namespace
CSharpTutorials.FirstProgram
3. We then declared a class using the class keyword: class Program
4. The Main() is a method of Program class is the entry point of the console application.
5. String is a data type.
6. A message is a variable that holds the value of a specified data type.
7. "Hello World!!" is the value of the message variable.
8. The Console.WriteLine() is a static method, which is used to display a text on the console.
Note:
Every line or statement in C# must end with a semicolon (;).
To see the output of the above C# program, we have to compile it and run it by pressing Ctrl + F5 or
clicking the Run button or by clicking the "Debug" menu and clicking "Start Without Debugging".
You will see the following output in the console:
Output:
Hello World!!
So this is the basic code items that you will probably use in every C# code.
C# Keywords
C# contains reserved words that have special meaning for the compiler. These reserved words are
called "keywords". Keywords cannot be used as an identifier (name of a variable, class, interface,
etc.).
Modifier Keywords
Modifier keywords are specific keywords that indicate who can modify types and type members.
Modifiers allow or prevent certain parts of programs from being modified by other parts.
Modifier keywords
abstract
async
const
event
extern
new
override
partial
readonly
sealed
static
unsafe
virtual
volatile
Access modifiers are applied to the declaration of the class, method, properties, fields, and other
members. They define the accessibility of the class and its members.
Access
Modifiers Usage
public The Public modifier allows any part of the program in the same assembly or another assembly
to access the type and its members.
private The Private modifier restricts other parts of the program from accessing the type and its
members. Only code in the same class or struct can access it.
internal The Internal modifier allows other program code in the same assembly to access the type or its
members. This is default access modifiers if no modifier is specified.
protected The Protected modifier allows codes in the same class or a class that derives from that class to
access the type or its members.
Statement Keywords
Statement Keywords
if
else
switch
case
do
for
foreach
in
while
break
continue
default
goto
return
yield
throw
try
catch
finally
checked
unchecked
fixed
lock
Namespace Keywords
These keywords are applied with namespace and related operators.
Namespace Keywords
using
. operator
:: operator
extern alias
ADVERTISEMENT
Operator Keywords
Operator Keywords
as
await
is
new
sizeof
typeof
stackalloc
checked
unchecked
Access Keywords
Access keywords are used to access the containing class or the base class of an object or class.
Access keywords
base
this
Literal Keywords
Literal Keywords
null
false
true
value
void
Type Keywords
Type keywords
bool
byte
Type keywords
char
class
decimal
double
enum
float
int
long
sbyte
short
string
struct
uint
ulong
ushort
Contextual Keywords
Contextual keywords are considered as keywords, only if used in specific contexts. They are not
reserved and so can be used as names or identifiers.
Contextual Keywords
add
var
dynamic
global
set
value
Contextual keywords are not converted into blue color (default color for keywords in visual studio)
when used as an identifier in Visual Studio. For example, var in the below figure is not in blue,
whereas the color of this is the blue color. So var is a contextual keyword.
C# Keywords
Query Keywords
Query Keywords
from
where
Query Keywords
select
group
into
orderby
join
let
in
on
equals
by
ascending
descending
As mentioned above, a keyword cannot be used as an identifier (name of the variable, class,
interface, etc.). However, they can be used with the prefix '@'. For example, the class is a reserved
keyword, so it cannot be used as an identifier, but @class can be used as shown below.
@class.MyProperty = 100;
Try it
C# Class
A class is like a blueprint of a specific object. In the real world, every object has some color, shape,
and functionalities - for example, the luxury car Ferrari. Ferrari is an object of the luxury car type.
The luxury car is a class that indicates some characteristics like speed, color, shape, interior, etc. So
any company that makes a car that meets those requirements is an object of the luxury car type. For
example, every single car of BMW, Lamborghini, Cadillac are an object of the class called 'Luxury
Car'. Here, 'Luxury Car' is a class, and every single physical car is an object of the luxury car class.
Likewise, in object-oriented programming, a class defines some properties, fields, events, methods,
etc. A class defines the kinds of data and the functionality their objects will have.
A class enables you to create your custom types by grouping variables of other types, methods, and
events.
Example: C# Class
public class MyClass
{
public string myField = string.Empty;
public MyClass()
{
}
C#
Class
C# Access Modifiers
Access modifiers are applied to the declaration of the class, method, properties, fields, and other
members. They define the accessibility of the class and its members. Public, private, protected, and
internal are access modifiers in C#.
C# Field
The field is a class-level variable that holds a value. Generally, field members should have a private
access modifier and used with property.
C# Constructor
A class can have parameterized or parameterless constructors. The constructor will be called when
you create an instance of a class. Constructors can be defined by using an access modifier and class
name: <access modifiers> <class name>(){ }
Example: Constructor in C#
class MyClass
{
public MyClass()
{
}
}
C# Method
Example: Method in C#
public void MyMethod(int parameter1, string parameter2)
{
// write your method code here..
Property
Example: Property in C#
private int _myPropertyVar;
Property encapsulates a private field. It provides getters (get{}) to retrieve the value of the
underlying field and setters (set{}) to set the value of the underlying field. In the above example,
_myPropertyVar is a private field that cannot be accessed directly. It will only be accessed via
MyProperty. Thus, MyProperty encapsulates _myPropertyVar.
You can also apply some additional logic in get and set, as in the below example.
Example: Property in C#
private int _myPropertyVar;
set {
if (value > 100)
_myPropertyVar = 100;
else
_myPropertyVar = value; ;
}
}
Auto-implemented Property
From C# 3.0 onwards, property declaration has been made easy if you don't want to apply some
logic in get or set.
Notice that there is no private backing field in the above property example. The backing field will be
created automatically by the compiler. You can work with an automated property as you would with
a normal property of the class. Automated-implemented property is just for easy declaration of the
property when no additional logic is required in the property accessors.
Namespace
The namespace is a container for a set of related classes and namespaces. The namespace is also
used to give unique names to classes within the namespace name. Namespace and classes are
represented using a dot (.).
Example: Namespace
namespace CSharpTutorials
{
class MyClass
{
}
}
In the above example, the fully qualified class name of MyClass is CSharpTutorials.MyClass.
A namespace can contain other namespaces. Inner namespaces can be separated using (.).
Example: Namespace
namespace CSharpTutorials.Examples
{
class MyClassExample
{
}
}
C# Variables
In C#, a variable contains a data value of the specific data type.
Syntax
<data type> <variable name> = <value>;
Example: C# Variable
int num = 100;
Above, int is a data type, num is a variable name (identifier). The = operator is used to assign a value
to a variable. The right side of the = operator is a value that will be assigned to left side variable.
Above, 100 is assigned to a variable num.
Example: C# Variables
int num = 100;
float rate = 10.2f;
decimal amount = 100.50M;
char code = 'C';
bool isValid = true;
string name = "Steve";
Try it
C# is the strongly typed language. It means you can assign a value of the specified data type. You
cannot assign an integer value to string type or vice-versa.
A variable must be assigned a value before using it, otherwise, C# will give a compile-time error.
Example: C# Variable
int num = 100;
num = 200;
Console.WriteLine(num); //output: 200
Multiple variables of the same data type can be declared and initialized in a single line separated by
commas.
Multiple variables of the same type can also be declared in multiple lines separated by a comma. The
compiler will consider it to be one statement until it encounters a semicolon ;.
The value of a variable can be assigned to another variable of the same data type. However, a value
must be assigned to a variable before using it.
In C#, variables are categorized based on how they store their value in memory. Variables can
be value type or reference type or pointer type.
It is not necessary to specify the specific type when declaring variables. Use the var keyword instead
of a data type. Learn about it next.
C# - var
In C#, variables must be declared with the data type. These are called explicitly typed variables.
C# 3.0 introduced var keyword to declare method level variables without specifying a data type
explicitly.
The compiler will infer the type of a variable from the expression on the right side of the = operator.
Above, var will be compiled as int.
}
Try it
var i = 100, j = 200, k = 300; // Error: cannot declare var variables in a single statement
C# - Data Types
C# is a strongly-typed language. It means we must declare the type of a variable that indicates the
kind of values it is going to store, such as integer, float, decimal, text, etc.
C# mainly categorized data types in two types: Value types and Reference types. Value types
include simple types (such as int, float, bool, and char), enum types, struct types, and Nullable value
types. Reference types include class types, interface types, delegate types, and array types. Learn
about value types and reference types in detail in the next chapter.
Predefined Data Types in C#
C# includes some predefined value types and reference types. The following table lists predefined
data types:
Suffi
Type Description Range x
byte 8-bit unsigned integer 0 to 255
sbyte 8-bit signed integer -128 to 127
short 16-bit signed integer -32,768 to 32,767
ushort 16-bit unsigned integer 0 to 65,535
int 32-bit signed integer -2,147,483,648
to
2,147,483,647
uint 32-bit unsigned integer 0 to 4,294,967,295 u
long 64-bit signed integer -9,223,372,036,854,775,808 l
to
9,223,372,036,854,775,807
ulong 64-bit unsigned integer 0 to 18,446,744,073,709,551,615 ul
float 32-bit Single-precision floating point type -3.402823e38 to 3.402823e38 f
double 64-bit double-precision floating point type -1.79769313486232e308 to d
1.79769313486232e308
decimal 128-bit decimal type for financial and (+ or -)1.0 x 10e-28 m
monetary calculations to
7.9 x 10e28
char 16-bit single Unicode character Any valid character, e.g. a,*, \x0058 (hex), or\
u0058 (Unicode)
bool 8-bit logical true/false value True or False
object Base type of all other types.
string A sequence of Unicode characters
DateTime Represents date and time 0:00:00am 1/1/01
to
Suffi
Type Description Range x
11:59:59pm 12/31/9999
As you can see in the above table that each data type (except string and object) includes value range.
The compiler will give an error if the value goes out of datatype's permitted range. For example, int
data type's range is -2,147,483,648 to 2,147,483,647. So if you assign a value which is not in this
range, then the compiler would give an error.
The value of unsigned integers, long, float, double, and decimal type must be suffix by u,l,f,d, and
m, respectively.
The predefined data types are alias to their .NET type (CLR class) name. The following table lists
alias for predefined data types and related .NET class name.
It means that whether you define a variable of int or Int32, both are the same.
int i = 345;
Int32 i = 345;// same as above
Default Values
Every data type has a default value. Numeric type is 0, boolean has false, and char has '\0' as default
value. Use the default(typename) to assign a default value of the data type or C# 7.1 onward,
use default literal.
int i = default(int); // 0
float f = default(float);// 0
decimal d = default(decimal);// 0
bool b = default(bool);// false
char c = default(char);// '\0'
// C# 7.1 onwards
int i = default; // 0
float f = default;// 0
decimal d = default;// 0
bool b = default;// false
char c = default;// '\0'
Conversions
The values of certain data types are automatically converted to different data types in C#. This is
called an implicit conversion.
In the above example, the value of an integer variable i is assigned to the variable of float
type f because this conversion operation is predefined in C#.
Conversions from int, uint, long, or ulong to float and from long or ulong to double may cause a loss
of precision. No data type implicitly converted to the char type.
However, not all data types are implicitly converted to other data types. For example, int type cannot
be converted to uint implicitly. It must be specified explicitly, as shown below.
Example: Explicit Conversion
public static void Main()
{
int i = 100;
uint u = (uint) i;
Console.Write(i);
}
In the above example, integer i is converted to uint explicitly by specifying uint in the brackets
(uint). This will convert an integer to uint
Numbers in C#
Numbers, in general, can be divided into two types: Integer type and floating-point types.
Integer type numbers are whole numbers without decimal points. It can be negative or positive
numbers.
Floating-point type is numbers with one or more decimal points. It can be negative or positive
numbers.
C# includes different data types for integer types and floating-point types based on their size in the
memory and capacity to store numbers.
Nume
ric Types
Integer Types
Integer type numbers are positive or negative whole numbers without decimal points. C# includes
four data types for integer numbers: byte, short, int, and long.
Byte
The byte data type stores numbers from 0 to 255. It occupies 8-bit in the memory. The byte keyword
is an alias of the Byte struct in .NET.
The sbyte is the same as byte, but it can store negative numbers from -128 to 127. The sbyte
keyword is an alias for SByte struct in .NET.
Console.WriteLine(Byte.MaxValue);//255
Console.WriteLine(Byte.MinValue);//0
Console.WriteLine(SByte.MaxValue);//127
Console.WriteLine(SByte.MinValue);//-128
Try it
Short
The short data type is a signed integer that can store numbers from -32,768 to 32,767. It occupies 16-
bit memory. The short keyword is an alias for Int16 struct in .NET.
The ushort data type is an unsigned integer. It can store only positive numbers from 0 to 65,535. The
ushort keyword is an alias for UInt16 struct in .NET.
Console.WriteLine(Int16.MaxValue);//32767
Console.WriteLine(Int16.MinValue);//-32768
Console.WriteLine(UInt16.MaxValue);//65535
Console.WriteLine(UInt16.MinValue);//0
Try it
Int
The int data type is 32-bit signed integer. It can store numbers from -2,147,483,648 to
2,147,483,647. The int keyword is an alias of Int32 struct in .NET.
The uint is 32-bit unsigned integer. The uint keyword is an alias of UInt32 struct in .NET. It can
store positive numbers from 0 to 4,294,967,295. Optionally use U or u suffix after a number to
assign it to uint variable.
Console.WriteLine(Int32.MaxValue);//2147483647
Console.WriteLine(Int32.MinValue);//-2147483648
Console.WriteLine(UInt32.MaxValue);//4294967295
Console.WriteLine(UInt32.MinValue);//0
Try it
The int data type is also used for hexadecimal and binary numbers. A hexadecimal number starts
with 0x or 0X prefix. C# 7.2 onwards, a binary number starts with 0b or 0B.
Example: Hexadecimal, Binary
int hex = 0x2F;
int binary = 0b_0010_1111;
Console.WriteLine(hex);
Console.WriteLine(binary);
Try it
ADVERTISEMENT
Long
The long type is 64-bit signed integers. It can store numbers from -9,223,372,036,854,775,808 to
9,223,372,036,854,775,807. Use l or L suffix with number to assign it to long type variable. The
long keyword is an alias of Int64 struct in .NET.
Console.WriteLine(Int64.MaxValue);//9223372036854775807
Console.WriteLine(Int64.MinValue);//-9223372036854775808
Console.WriteLine(UInt64.MaxValue);//18446744073709551615
Console.WriteLine(UInt64.MinValue);//0
Try it
Floating-point numbers are positive or negative numbers with one or more decimal points. C#
includes three data types for floating-point numbers: float, double, and decimal.
Float
The float data type can store fractional numbers from 3.4e−038 to 3.4e+038. It occupies 4 bytes in
the memory. The float keyword is an alias of Single struct in .NET.
Example: float
float f1 = 123456.5F;
float f2 = 1.123456f;
Console.WriteLine(f1);//123456.5
Console.WriteLine(f2);//1.123456
Try it
Double
The double data type can store fractional numbers from 1.7e−308 to 1.7e+308. It occupies 8 bytes in
the memory. The double keyword is an alias of the Double struct in .NET.
Example: double
double d1 = 12345678912345.5d;
double d2 = 1.123456789123456d;
Console.WriteLine(d1);//12345678912345.5
Console.WriteLine(d2);//1.123456789123456
Try it
Decimal
The decimal data type can store fractional numbers from ±1.0 x 10-28 to ±7.9228 x 1028. It occupies
16 bytes in the memory. The decimal is a keyword alias of the Decimal struct in .NET.
The decimal type has more precision and a smaller range than both float and double, and so it is
appropriate for financial and monetary calculations.
Example: decimal
decimal d1 = 123456789123456789123456789.5m;
decimal d2 = 1.1234567891345679123456789123m;
Console.WriteLine(d1);
Console.WriteLine(d2);
Try it
Scientific Notation
Use e or E to indicate the power of 10 as exponent part of scientific notation with float, double or
decimal.
Example:
double d = 0.12e2;
Console.WriteLine(d); // 12;
float f = 123.45e-2f;
Console.WriteLine(f); // 1.2345
decimal m = 1.2e6m;
Console.WriteLine(m);// 1200000
Try it
C# Strings
In C#, a string is a series of characters that is used to represent text. It can be a character, a word or a
long passage surrounded with the double quotes ". The following are string literals.
The maximum size of a String object in memory is 2GB or about 1 billion characters. However,
practically it will be less depending upon CPU and memory of the computer.
There two ways to declare a string variable in C#. Using System.String class and
using string keyword. Both are the same and make no difference. Learn string vs String for more
info.
In C#, a string is a collection or an array of characters. So, string can be created using a char array or
accessed like a char array.
Special Characters
A text in the real world can include any character. In C#, because a string is surrounded with double
quotes, it cannot include " in a string. The following will give a compile-time error.
C# includes escaping character \ (backslash) before these special characters to include in a string.
Use backslash \ before double quotes and some special characters such as \,\n,\r,\t, etc. to include it
in a string.
Please note that you must use a backslash to allow " in a string. @ is only for special characters in
C#.
String Concatenation
string agent = "Mr." + firstName + " " + lastName + ", Code: " + code;
Try it
A String is immutable in C#. It means it is read-only and cannot be changed once created in the
memory. Each time you concatenate strings, .NET CLR will create a new memory location for the
concatenated string. So, it is recommended to use StringBuilder instead of string if you concatenate
more than five strings.
String Interpolation
String interpolation is a better way of concatenating strings. We use + sign to concatenate string
variables with static strings.
In the above example of interpolation, $ indicates the interpolated string, and {} includes string
variable to be incorporated with a string.
To work with date and time in C#, create an object of the DateTime struct using the new keyword.
The following creates a DateTime object with the default value.
The default and the lowest value of a DateTime object is January 1, 0001 00:00:00 (midnight). The
maximum value can be December 31, 9999 11:59:59 P.M.
Use different constructors of the DateTime struct to assign an initial value to a DateTime object.
In the above example, we specified a year, a month, and a day in the constructor. The year can be
from 0001 to 9999, and the Month can be from 1 to 12, and the day can be from 1 to 31. Setting any
other value out of these ranges will result in a run-time exception.
Use different DateTime constructors to set date, time, time zone, calendar, and culture.
Ticks
Ticks is a date and time expressed in the number of 100-nanosecond intervals that have elapsed since
January 1, 0001, at 00:00:00.000 in the Gregorian calendar. The following initializes
a DateTime object with the number of ticks.
Example: Ticks
DateTime dt = new DateTime(636370000000000000);
DateTime.MinValue.Ticks; //min value of ticks
DateTime.MaxValue.Ticks; // max value of ticks
Try it
The DateTime struct includes static fields, properties, and methods. The following example
demonstrates important static fields and properties.
TimeSpan
TimeSpan is a struct that is used to represent time in days, hour, minutes, seconds, and milliseconds.
Example: TimeSpan
DateTime dt = new DateTime(2015, 12, 31);
Console.WriteLine(newDate);//1/1/2016 1:20:55 AM
Try it
Operators
The DateTime struct overloads +, -, ==, !=, >, <, <=, >= operators to ease out addition, subtraction,
and comparison of dates. These make it easy to work with dates.
Example: Operators
DateTime dt1 = new DateTime(2015, 12, 20);
DateTime dt2 = new DateTime(2016, 12, 31, 5, 10, 20);
TimeSpan time = new TimeSpan(10, 5, 25, 50);
The Parse() and ParseExact() methods will throw an exception if the specified string is not a valid
representation of a date and time. So, it's recommended to use TryParse() or TryParseExact() method
because they return false if a string is not valid.
Example:
var str = "5/12/2020";
DateTime dt;
if(isValidDate)
Console.WriteLine(dt);
else
Console.WriteLine($"{str} is not a valid date string");
Try it
C# - StringBuilder
In C#, the string type is immutable. It means a string cannot be changed once created. For example, a
new string, "Hello World!" will occupy a memory space on the heap. Now, by changing the initial
string "Hello World!" to "Hello World! from Tutorials Teacher" will create a new string object on
the memory heap instead of modifying an original string at the same memory address. This behavior
would hinder the performance if the original string changed multiple times by replacing, appending,
removing, or inserting new strings in the original string.
Memory Allocation for String Object
You can create an object of the StringBuilder class using the new keyword and passing an initial
string. The following example demonstrates creating StringBuilder objects.
Example: StringBuilder
using System.Text; // include at the top
Optionally, you can also specify the maximum capacity of the StringBuilder object using overloaded
constructors, as shown below.
Example: StringBuilder
StringBuilder sb = new StringBuilder(50); //string will be appended later
//or
StringBuilder sb = new StringBuilder("Hello World!", 50);
Above, C# allocates a maximum of 50 spaces sequentially on the memory heap. This capacity will
automatically be doubled once it reaches the specified capacity. You can also use
the capacity or length property to set or retrieve the StringBuilder object's capacity.
You can iterate the using for loop to get or set a character at the specified index.
The StringBuilder is not the string. Use the ToString() method to retrieve a string from
the StringBuilder object.
Use the Append() method to append a string at the end of the current StringBuilder object. If
a StringBuilder does not contain any string yet, it will add it. The AppendLine() method append a
string with the newline character at the end.
Hello World!
Hello C#.
Use the AppendFormat() method to format an input string into the specified format and append it.
Example: AppendFormat()
StringBuilder sbAmout = new StringBuilder("Your total amount is ");
sbAmout.AppendFormat("{0:C} ", 25);
Use the Insert() method inserts a string at the specified index in the StringBuilder object.
Example: Insert()
StringBuilder sb = new StringBuilder("Hello World!");
sb.Insert(5," C#");
Use the Remove() method to remove a string from the specified index and up to the specified length.
Example: Remove()
StringBuilder sb = new StringBuilder("Hello World!",50);
sb.Remove(6, 7);
Use the Replace() method to replace all the specified string occurrences with the specified
replacement string.
Example: Replace()
StringBuilder sb = new StringBuilder("Hello World!");
sb.Replace("World", "C#");
1. StringBuilder is mutable.
2. StringBuilder performs faster than string when appending multiple string values.
3. Use StringBuilder when you need to append more than three or four strings.
4. Use the Append() method to add or append strings to the StringBuilder object.
5. Use the ToString() method to retrieve a string from the StringBuilder object.
In C#, these data types are categorized based on how they store their value in the memory. C#
includes the following categories of data types:
1. Value type
2. Reference type
3. Pointer type
Value Type
A data type is a value type if it holds a data value within its own memory space. It means the
variables of these data types directly contain values.
All the value types derive from System.ValueType, which in-turn, derives
from System.Object.
The system stores 100 in the memory space allocated for the variable i. The following image
illustrates how 100 is stored at some hypothetical location in the memory (0x239110) for 'i':
bool
byte
char
decimal
double
enum
float
int
long
sbyte
short
struct
uint
ulong
ushort
When you pass a value-type variable from one method to another, the system creates a separate copy
of a variable in another method. If value got changed in the one method, it wouldn't affect the
variable in another method.
Console.WriteLine(x);
}
static void Main(string[] args)
{
int i = 100;
Console.WriteLine(i);
ChangeValue(i);
Console.WriteLine(i);
}
Try it
Output:
100
200
100
In the above example, variable i in the Main() method remains unchanged even after we pass it to
the ChangeValue() method and change it's value there.
ADVERTISEMENT
Reference Type
Unlike value types, a reference type doesn't store its value directly. Instead, it stores the address
where the value is being stored. In other words, a reference type contains a pointer to another
memory location that holds the data.
The following image shows how the system allocates the memory for the above string variable.
Memory Allocation of
Reference Type Variable
As you can see in the above image, the system selects a random location in memory (0x803200) for
the variable s. The value of a variable s is 0x600000, which is the memory address of the actual data
value. Thus, reference type stores the address of the location where the actual value is stored instead
of the value itself.
The followings are reference type data types:
String
Arrays (even if their elements are value types)
Class
Delegate
When you pass a reference type variable from one method to another, it doesn't create a new copy;
instead, it passes the variable's address. So, If we change the value of a variable in a method, it will
also be reflected in the calling method.
ChangeReferenceType(std1);
Console.WriteLine(std1.StudentName);
}
Try it
Output:
Steve
In the above example, we pass the Student object std1 to the ChangeReferenceType() method. Here,
it actually pass the memory address of std1. Thus, when the ChangeReferenceType() method
changes StudentName, it is actually changing StudentName of std1 object, because std1 and std2 are
both pointing to the same address in memory.
String is a reference type, but it is immutable. It means once we assigned a value, it cannot be
changed. If we change a string value, then the compiler creates a new string object in the memory
and point a variable to the new memory location. So, passing a string value to a function will create
a new variable in the memory, and any change in the value in the function will not be reflected in the
original value, as shown below.
ChangeReferenceType(name);
Console.WriteLine(name);
}
Try it
Output:
Bill
Null
The default value of a reference type variable is null when they are not initialized. Null means not
refering to any object.
A value type variable cannot be null because it holds value, not a memory address. C# 2.0
introduced nullable types, using which you can assign null to a value type variable or declare a value
type variable without assigning a value to it.
C# - Interface
In the human world, a contract between the two or more humans binds them to act as per the
contract. In the same way, an interface includes the declarations of related functionalities. The
entities that implement the interface must provide the implementation of declared functionalities.
In C#, an interface can be defined using the interface keyword. An interface can contain declarations
of methods, properties, indexers, and events. However, it cannot contain fields, auto-implemented
properties.
The following interface declares some basic functionalities for the file operations.
Example: C# Interface
interface IFile
{
void ReadFile();
void WriteFile(string text);
}
You cannot apply access modifiers to interface members. All the members are public by default. If
you use an access modifier in an interface, then the C# compiler will give a compile-time error "The
modifier 'public/private/protected' is not valid for this item.". (Visual Studio will show an error
immediately without compilation.)
An interface can only contain declarations but not implementations. The following will give a
compile-time error.
Implementing an Interface
A class or a Struct can implement one or more interfaces using colon (:).
For example, the following class implements the IFile interface implicitly.
In the above example, the FileInfo class implements the IFile interface. It defines all the members of
the IFile interface with public access modifier. The FileInfo class can also contain members other
than interface members.
Note:
Interface members must be implemented with the public modifier; otherwise, the compiler will give
compile-time errors.
You can create an object of the class and assign it to a variable of an interface type, as shown below.
file1.ReadFile();
file1.WriteFile("content");
file2.ReadFile();
file2.WriteFile("content");
}
}
Try it
Above, we created objects of the FileInfo class and assign it to IFile type variable and FileInfo type
variable. When interface implemented implicitly, you can access IFile members with the IFile type
variables as well as FileInfo type variable.
ADVERTISEMENT
Explicit Implementation
Note:
Do not use public modifier with an explicit implementation. It will give a compile-time error.
Example: Explicit Implementation
interface IFile
{
void ReadFile();
void WriteFile(string text);
}
When you implement an interface explicitly, you can access interface members only through the
instance of an interface type.
file1.ReadFile();
file1.WriteFile("content");
//file1.Search("text to be searched")//compile-time error
file2.Search("text to be searched");
//file2.ReadFile(); //compile-time error
//file2.WriteFile("content"); //compile-time error
}
}
Try it
In the above example, file1 object can only access members of IFile, and file2 can only access
members of FileInfo class. This is the limitation of explicit implementation.
A class or struct can implement multiple interfaces. It must provide the implementation of all the
members of all interfaces.
interface IBinaryFile
{
void OpenBinaryFile();
void ReadFile();
}
void IBinaryFile.OpenBinaryFile()
{
Console.WriteLine("Opening Binary File");
}
void IBinaryFile.ReadFile()
{
Console.WriteLine("Reading Binary File");
}
file1.ReadFile();
//file1.OpenBinaryFile(); //compile-time error
//file1.SearchFile("text to be searched"); //compile-time error
file2.OpenBinaryFile();
file2.ReadFile();
//file2.SearchFile("text to be searched"); //compile-time error
file3.Search("text to be searched");
//file3.ReadFile(); //compile-time error
//file3.OpenBinaryFile(); //compile-time error
}
}
Try it
Above, the FileInfo implements two interfaces IFile and IBinaryFile explicitly. It is recommended to
implement interfaces explicitly when implementing multiple interfaces to avoid confusion and more
readability.
Points to Remember :
1. Interface can contain declarations of method, properties, indexers, and events.
2. Interface cannot include private, protected, or internal members. All the members are public by
default.
3. Interface cannot contain fields, and auto-implemented properties.
4. A class or a struct can implement one or more interfaces implicitly or explicitly. Use public modifier
when implementing interface implicitly, whereas don't use it in case of explicit implementation.
5. Implement interface explicitly using InterfaceName.MemberName.
6. An interface can inherit one or more interfaces.
C# Operators
Operators in C# are some special symbols that perform some action on operands. In mathematics,
the plus symbol (+) do the sum of the left and right numbers. In the same way, C# includes various
operators for different types of operations.
Example: + Operator
int x = 5 + 5;
int y = 10 + x;
int z = x + y;
Try it
In the above example, + operator adds two number literals and assign the result to a variable. It also
adds the values of two int variables and assigns the result to a variable.
Some operators behave differently based on the type of the operands. For example, + operator
concatenates two strings.
Arithmetic operators
Assignment operators
Comparison operators
Equality operators
Boolean logical operators
Betwise and shift operators
Member access operators
Type-cast operators
Pointer related operators
Arithmetic Operators
The arithmetic operators perform arithmetic operations on all the numeric type operands such as
sbyte, byte, short, ushort, int, uint, long, ulong, float, double, and decimal.
Assignment Operators
The assignment operator = assigns its right had value to its left-hand variable, property, or indexer. It
can also be used with other arithmetic, Boolean logical, and bitwise operators.
Operato
r Name Description Example
= Assignment Assigns its right had value to its left-hand variable, property or x = 10; Try
indexer. it
x op= y Compound Short form of x =x op y where op = any arithmetic, Boolean x += 5; Try
assignment logical, and bitwise operator. it
??= Null-coalescing C# 8 onwards, ??= assigns value of the right operand only if the x ??= 5; Try
assignment left operand is null it
Comparison Operators
Comparison operators compre two numeric operands and returns true or false.
Equality Operators
The equality operator checks whether the two operands are equal or not.
Operato
r Description Example
! Reverses the bool result of bool expression. Returns false if result is true and returns !false Try
true if result is false. it
&& Computes the logical AND of its bool operands. Returns true both operands are true, x && y; Try
otherwise returns false. it
|| Computes the logical OR of its bool operands. Returns true when any one operand is x || y; Try
true. it
Evaluation of the operands in an expression starts from left to right. If multiple operators are used in
an expression, then the operators with higher priority are evaluated before the operators with lower
priority.
The following table lists operators starting with the higher precedence operators to lower precedence
operators.
Operators Category
x.y, x?.y, x?[y], f(x), a[i], x++, x--, new, typeof, checked, unchecked, default, Primary
nameof, delegate, sizeof, stackalloc, x->y
+x, -x, !x, ~x, ++x, --x, ^x, (T)x, await, &x, *x, true and false Unary
x..y Range
x * y, x / y, x % y Multiplicative
x + y, x � y Additive
x << y, x >> y Shift
x < y, x > y, x <= y, x >= y, is, as Relational and type-testing
x == y, x != y Equality
x&y Boolean logical AND
x^y Boolean logical XOR
x|y Boolean logical OR
x && y Conditional AND
x || y Conditional OR
x ?? y Null-coalescing operator
c?t:f Conditional operator
x = y, x += y, x -= y, x *= y, x /= y, x %= y, x &= y, x |= y, x ^= y, x <<= y, x >>= Assignment and lambda
y, x ??= y, => declaration
C# provides many decision-making statements that help the flow of the C# program based on certain
logical conditions. Here, you will learn about if, else if, else, and nested if else statements to control
the flow based on the conditions.
1. if statement
2. else-if statement
3. else statement
C# if Statement
The if statement contains a boolean condition followed by a single or multi-line code block to be
executed. At runtime, if a boolean condition evaluates to true, then the code block will be executed,
otherwise not.
Syntax:
if(condition)
{
// code block to be executed when if condition evaluates to true
}
Example: if Statement
int i = 10, j = 20;
if (i < j)
{
Console.WriteLine("i is less than j");
}
if (i > j)
{
Console.WriteLine("i is greater than j");
}
Try it
Output:
i is less than j
In the above example, a boolean condition in the first if statement i < j evaluates to true, so the C#
compiler will execute the following code block. The second if statement's condition i > j evaluates to
false, so the compiler will not execute its code block.
The conditional expression must return a boolean value, otherwise C# compiler will give a compile-
time error.
if (i + 1)
{
Console.WriteLine("i is less than j");
}
if (i + j)
{
Console.WriteLine("i is greater than j");
}
You can call a function in the if statement that returns a boolean value.
if (isGreater(i, j))
{
Console.WriteLine("i is less than j");
}
if (isGreater(j, i))
{
Console.WriteLine("j is greater than i");
}
}
else if Statement
Multiple else if statements can be used after an if statement. It will only be executed when
the if condition evaluates to false. So, either if or one of the else if statements can be executed, but
not both.
Syntax:
if(condition1)
{
// code block to be executed when if condition1 evaluates to true
}
else if(condition2)
{
// code block to be executed when
// condition1 evaluates to flase
// condition2 evaluates to true
}
else if(condition3)
{
// code block to be executed when
// condition1 evaluates to flase
// condition2 evaluates to false
// condition3 evaluates to true
}
The following example demonstrates else if statements.
if (i == j)
{
Console.WriteLine("i is equal to j");
}
else if (i > j)
{
Console.WriteLine("i is greater than j");
}
else if (i < j)
{
Console.WriteLine("i is less than j");
}
Try it
Output:
i is less than j
ADVERTISEMENT
else Statement
The else statement can come only after if or else if statement and can be used only once in the if-
else statements. The else statement cannot contain any condition and will be executed when all the
previous if and else if conditions evaluate to false.
if (i > j)
{
Console.WriteLine("i is greater than j");
}
else if (i < j)
{
Console.WriteLine("i is less than j");
}
else
{
Console.WriteLine("i is equal to j");
}
Try it
Output:
i is equal to j
Nested if Statements
C# supports if else statements inside another if else statements. This are called nested if
else statements. The nested if statements make the code more readable.
Syntax:
if(condition1)
{
if(condition2)
{
// code block to be executed when
// condition1 and condition2 evaluates to true
}
else if(condition3)
{
if(condition4)
{
// code block to be executed when
// only condition1, condition3, and condition4 evaluates to true
}
else if(condition5)
{
// code block to be executed when
// only condition1, condition3, and condition5 evaluates to true
}
else
{
// code block to be executed when
// condition1, and condition3 evaluates to true
// condition4 and condition5 evaluates to false
}
}
}
if (i != j)
{
if (i < j)
{
Console.WriteLine("i is less than j");
}
else if (i > j)
{
Console.WriteLine("i is greater than j");
}
}
else
Console.WriteLine("i is equal to j");
Try it
Output:
i is less than j
C# - Ternary Operator ?:
Updated on: June 24, 2020
Syntax:
condition ? statement 1 : statement 2
The ternary operator starts with a boolean condition. If this condition evaluates to true then it will
execute the first statement after ?, otherwise the second statement after : will be executed.
var result = x > y ? "x is greater than y" : "x is less than y";
Console.WriteLine(result);
Try it
output:
x is greater than y
Above, a conditional expression x > y returns true, so the first statement after ? will be execute.
var result = x > y ? "x is greater than y" : "x is less than y";
Console.WriteLine(result);
output:
x is less than y
Thus, a ternary operator is short form of if else statement. The above example can be re-write
using if else condition, as shown below.
if (x > y)
Console.WriteLine("x is greater than y");
else
Console.WriteLine("x is less than y");
Try it
output:
x is greater than y
Nested ternary operators are possible by including a conditional expression as a second statement.
Example: Nested ?:
int x = 10, y = 100;
Console.WriteLine(result);
Try it
Example: Nested ?:
var x = 2, y = 10;
C# - Switch Statement
The switch statement can be used instead of if else statement when you want to test a variable
against three or more conditions. Here, you will learn about the switch statement and how to use it
efficiently in the C# program.
Syntax:
switch(match expression/variable)
{
case constant-value:
statement(s) to be executed;
break;
default:
statement(s) to be executed;
break;
}
The switch statement starts with the switch keyword that contains a match expression or a variable in
the bracket switch(match expression). The result of this match expression or a variable will be tested
against conditions specified as cases, inside the curly braces { }. A case must be specified with the
unique constant value and ends with the colon :. Each case includes one or more statements to be
executed. The case will be executed if a constant value and the value of a match expression/variable
are equal. The switch statement can also contain an optional default label. The default label will be
executed if no cases executed. The break, return, or goto keyword is used to exit the program control
from a switch case.
switch (x)
{
case 5:
Console.WriteLine("Value of x is 5");
break;
case 10:
Console.WriteLine("Value of x is 10");
break;
case 15:
Console.WriteLine("Value of x is 15");
break;
default:
Console.WriteLine("Unknown value");
break;
}
Try it
Output:
Value of x is 10
Above, the switch(x) statement includes a variable x whose value will be matched with the value of
each case value. The above switch statement contains three cases with constant values 5, 10, and 15.
It also contains the default label, which will be executed if none of the case value match with the
switch variable/expression. Each case starts after : and includes one statement to be executed. The
value of x matches with the second case case 10:, so the output would be Value of x is 10.
Note:
The switch statement can include any non-null expression that returns a value of type: char, string, bool,
int, or enum.
The switch statement can also include an expression whose result will be tested against each case at
runtime.
switch (x % 2)
{
case 0:
Console.WriteLine($"{x} is an even value");
break;
case 1:
Console.WriteLine($"{x} is an odd Value");
break;
}
Try it
Output:
ADVERTISEMENT
Switch Case
The switch cases must be unique constant values. It can be bool, char, string, integer, enum, or
corresponding nullable type.
Note
C# 7.0 onward, switch cases can include non-unique values. In this case, the first matching case will be
executed.
switch (statementType)
{
case "if.else":
Console.WriteLine("if...else statement");
break;
case "ternary":
Console.WriteLine("Ternary operator");
break;
case "switch":
Console.WriteLine("switch statement");
break;
}
Try it
Output:
switch statement
switch (x)
{
case 1:
Console.WriteLine("x = 1");
break;
case 2:
Console.WriteLine("x = 2");
break;
case 4:
case 5:
Console.WriteLine("x = 4 or x = 5");
break;
default:
Console.WriteLine("x > 5");
break;
}
Try it
Each case must exit the case explicitly by using break, return, goto statement, or some other way,
making sure the program control exits a case and cannot fall through to the default case.
return false;
}
Try it
Output:
Odd value
The switch cases without break, return, or goto statement or with the same constant values would
give a compile-time error.
switch (x)
{
case 0:
Console.WriteLine($"{x} is even value");
break;
case 1:
Console.WriteLine($"{x} is odd Value");
break;
case 1: // Error - Control cannot fall through from one case label ('case 1:') to another
Console.WriteLine($"{x} is odd Value");
defaut:
Console.WriteLine($"{x} is odd Value");
break;
}
switch (j)
{
case 5:
Console.WriteLine(5);
switch (j - 1)
{
case 4:
Console.WriteLine(4);
switch (j - 2)
{
case 3:
Console.WriteLine(3);
break;
}
break;
}
break;
case 10:
Console.WriteLine(10);
break;
case 15:
Console.WriteLine(15);
break;
default:
Console.WriteLine(100);
break;
}
Try it
Output:
Points to Remember :
C# for Loop
Here, you will learn how to execute a statement or code block multiple times using the for loop,
structure of the for loop, nested for loops, and how to exit from the for loop.
The for keyword indicates a loop in C#. The for loop executes a block of statements repeatedly until
the specified condition returns false.
Syntax:
for (initializer; condition; iterator)
{
//code block
}
The for loop contains the following three optional sections, separated by a semicolon:
Initializer: The initializer section is used to initialize a variable that will be local to a for loop and
cannot be accessed outside loop. It can also be zero or more assignment statements, method call,
increment, or decrement expression e.g., ++i or i++, and await expression.
Condition: The condition is a boolean expression that will return either true or false. If an
expression evaluates to true, then it will execute the loop again; otherwise, the loop is exited.
Iterator: The iterator defines the incremental or decremental of the loop variable.
Value of i: 0
Value of i: 1
Value of i: 2
Value of i: 3
Value of i: 4
Value of i: 5
Value of i: 6
Value of i: 7
Value of i: 8
Value of i: 9
In the above example, int i = 0 is an initializer where we define an int variable i and initialize it with
0. The second section is the condition expression i < 10, if this condition returns true then it will
execute a code block. After executing the code block, it will go to the third section, iterator. The i+
+ is an incremental statement that increases the value of a loop variable i by 1. Now, it will check the
conditional expression again and repeat the same thing until conditional expression returns false.
The below figure illustrates the execution steps of the for loop.
The below figure illustrates the execution steps of the for loop.
If a code block only contains a single statement, then you don't need to wrap it inside curly
brackets { }, as shown below.
An Initializer, condition, and iterator sections are optional. You can initialize a variable
before for loop, and condition and iterator can be defined inside a code block, as shown below.
for(;;)
{
if (i < 10)
{
Console.WriteLine("Value of i: {0}", i);
i++;
}
else
break;
}
Try it
Output:
Value of i: 0
Value of i: 1
Value of i: 2
Value of i: 3
Value of i: 4
Value of i: 5
Value of i: 6
Value of i: 7
Value of i: 8
Value of i: 9
Since all three sections are optional in the for loop, be careful in defining a condition and iterator.
Otherwise, it will be an infinite loop that will never end the loop.
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1.....
The control variable for the for loop can be of any numeric data type, such as double, decimal, etc.
Value of i: 1.01
Value of i: 1.02
Value of i: 1.03
Value of i: 1.04
Value of i: 1.05
Value of i: 1.06
Value of i: 1.07
Value of i: 1.08
Value of i: 1.09
The steps part in a for loop can either increase or decrease the value of a variable.
Value of i: 10
Value of i: 9
Value of i: 8
Value of i: 7
Value of i: 6
Value of i: 5
Value of i: 4
Value of i: 3
Value of i: 2
Value of i: 1
You can also exit from a for loop by using the break keyword.
Value of i: 0
Value of i: 1
Value of i: 2
Value of i: 3
Value of i: 4
Multiple Expressions
A for loop can also include multiple initializer and iterator statements separated by comma, as shown
below.
Value of i: 1, J: 1
Value of i: 2, J: 2
Value of i: 0, J: 0
Value of i: 0, J: 1
Value of i: 0, J: 2
Value of i: 0, J: 3
Value of i: 1, J: 1
Value of i: 1, J: 2
Value of i: 1, J: 3
C# - while Loop
C# provides the while loop to repeatedly execute a block of code as long as the specified condition
returns false.
Syntax:
While(condition)
{
//code block
}
The while loop starts with the while keyword, and it must include a boolean conditional expression
inside brackets that returns either true or false. It executes the code block until the specified
conditional expression returns false.
The for loop contains the initialization and increment/decrement parts. When using the while loop,
initialization should be done before the loop starts, and increment or decrement steps should be
inside the loop.
i++; // increment
}
Try it
Output:
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i=9
Above, a while loop includes an expression i < 10. Inside a while loop, the value of i increased to 1
using i++. The above while loop will be executed when the value of i equals to 10 and a condition i
< 10 returns false.
Use the break or return keyword to exit from a while loop on some condition, as shown below.
while (true)
{
Console.WriteLine("i = {0}", i);
i++;
if (i > 10)
break;
}
Try it
Ensure that the conditional expression evaluates to false or exit from the while loop on some
condition to avoid an infinite loop. The following loop is missing an appropriate condition or break
the loop, which makes it an infinite while loop.
while (i > 0)
{
Console.WriteLine("i = {0}", i);
i++;
}
C# allows while loops inside another while loop, as shown below. However, it is not recommended
to use nested while loop because it makes it hard to debug and maintain.
Example: Nested while Loop
int i = 0, j = 1;
while (i < 2)
{
Console.WriteLine("i = {0}", i);
i++;
while (j < 2)
{
Console.WriteLine("j = {0}", j);
j++;
}
}
Try it
Output:
i = 0
j = 1
i=1
C# - do while Loop
The do while loop is the same as while loop except that it executes the code block at least once.
Syntax:
do
{
//code block
} while(condition);
The do-while loop starts with the do keyword followed by a code block and a boolean expression
with the while keyword. The do while loop stops execution exits when a boolean condition evaluates
to false. Because the while(condition) specified at the end of the block, it certainly executes the code
block at least once.
do
{
Console.WriteLine("i = {0}", i);
i++;
i = 1
i = 2
i = 3
i=4
Specify initialization out of the loop and increment/decrement counter inside do while loop.
do
{
Console.WriteLine("i = {0}", i);
i++;
if (i > 5)
break;
i = 0
i = 1
i = 2
i = 3
i = 4
i=5
Nested do-while
do
{
Console.WriteLine("Value of i: {0}", i);
int j = i;
i++;
do
{
Console.WriteLine("Value of j: {0}", j);
j++;
} while (j < 2);
i = 0
j = 0
j = 1
i = 1
j=1
In C#, static means something which cannot be instantiated. You cannot create an object of a static
class and cannot access static members using an object.
C# classes, variables, methods, properties, operators, events, and constructors can be defined as
static using the static modifier keyword.
Static Class
Apply the static modifier before the class name and after the access modifier to make a class static.
The following defines a static class with static fields and methods.
Above, the Calculator class is a static. All the members of it are also static.
You cannot create an object of the static class; therefore the members of the static class can be
accessed directly using a class name like ClassName.MemberName, as shown below.
The normal class (non-static class) can contain one or more static methods, fields, properties, events
and other non-static members.
It is more practical to define a non-static class with some static members, than to declare an entire
class as static.
Static Fields
Static fields in a non-static class can be defined using the static keyword.
Static fields of a non-static class is shared across all the instances. So, changes done by one instance
would reflect in others.
class Program
{
static void Main(string[] args)
{
StopWatch sw1 = new StopWatch();
StopWatch sw2 = new StopWatch();
Console.WriteLine(StopWatch.NoOfInstances); //2
Static Methods
You can define one or more static methods in a non-static class. Static methods can be called without
creating an object. You cannot call static methods using an object of the non-static class.
The static methods can only call other static methods and access static members. You cannot access
non-static members of the class in the static methods.
1. Static methods can be defined using the static keyword before a return type and after an access
modifier.
2. Static methods can be overloaded but cannot be overridden.
3. Static methods can contain local static variables.
4. Static methods cannot access or call non-static variables unless they are explicitly passed as
parameters.
Static Constructors
A non-static class can contain a parameterless static constructor. It can be defined with the static
keyword and without access modifiers like public, private, and protected.
The following example demonstrates the difference between static constructor and instance
constructor.
// instance constructor
public StopWatch()
{
Console.WriteLine("Instance constructor called");
}
// static method
public static void DisplayInfo()
{
Console.WriteLine("DisplayInfo called");
}
// instance method
public void Start() { }
// instance method
public void Stop() { }
}
Try it
Above, the non-static class StopWatch contains a static constructor and also a non-static constructor.
The static constructor is called only once whenever the static method is used or creating an instance
for the first time. The following example shows that the static constructor gets called when the static
method called for the first time. Calling the static method second time onwards won't call a static
constructor.
DisplayInfo called
DisplayInfo called
The following example shows that the static constructor gets called when you create an instance for
the first time.
DisplayInfo called
1. The static constructor is defined using the static keyword and without using access modifiers
public, private, or protected.
2. A non-static class can contain one parameterless static constructor. Parameterized static
constructors are not allowed.
3. Static constructor will be executed only once in the lifetime. So, you cannot determine when it
will get called in an application if a class is being used at multiple places.
4. A static constructor can only access static members. It cannot contain or access instance
members.
Note:
Static members are stored in a special area in the memory called High-Frequency Heap. Static members
of non-static classes are shared across all the instances of the class. So, the changes done by one
instance will be reflected in all the other instances.
C# Arrays
Updated on: May 10, 2020
A variable is used to store a literal value, whereas an array is used to store multiple literal values.
An array is the data structure that stores a fixed number of literal values (elements) of the same data
type. Array elements are stored contiguously in the memory.
In C#, an array can be of three types: single-dimensional, multidimensional, and jagged array. Here
you will learn about the single-dimensional array.
Array Representation
An array can be declared using by specifying the type of its elements with square brackets.
The following declares and adds values into an array in a single statement.
Above, evenNums array can store up to five integers. The number 5 in the square brackets new
int[5] specifies the size of an array. In the same way, the size of cities array is three. Array elements
are added in a comma-separated list inside curly braces { }.
Arrays type variables can be declared using var without square brackets.
If you are adding array elements at the time of declaration, then size is optional. The compiler will
infer its size based on the number of elements inside curly braces, as shown below.
Late Initialization
It is not necessary to declare and initialize an array in a single statement. You can first declare an
array then initialize it later on using the new operator.
Array elements can be accessed using an index. An index is a number associated with each array
element, starting with index 0 and ending with array size - 1.
The following example add/update and retrieve array elements using indexes.
Console.WriteLine(evenNums[0]); //prints 2
Console.WriteLine(evenNums[1]); //prints 4
Try it
Note that trying to add more elements than its specified size will result
in IndexOutOfRangeException.
Use the for loop to access array elements. Use the length property of an array in conditional
expression of the for loop.
Use foreach loop to read values of an array elements without using index.
LINQ Methods
All the arrays in C# are derived from an abstract base class System.Array.
The Array class implements the IEnumerable interface, so you can LINQ extension methods such
as Max(), Min(), Sum(), reverse(), etc. See the list of all extension methods here.
nums.Max(); // returns 16
nums.Min(); // returns 6
nums.Sum(); // returns 55
nums.Average(); // returns 55
Try it
The System.Array class also includes methods for creating, manipulating, searching, and sorting
arrays. See list of all Array methods here.
An array can be passed as an argument to a method parameter. Arrays are reference types, so the
method can change the value of the array elements.
Example: Passing Array as Argument
public static void Main(){
int[] nums = { 1, 2, 3, 4, 5 };
UpdateArray(nums);
C# - Multidimensional Arrays
Let's understand the two-dimensional array. The following initializes the two-dimensional array.
// or
int[,] arr2d = {
{1, 2},
{3, 4},
{5, 6}
};
In the above example of a two-dimensional array, [3, 2] defines the no of rows and columns. The
first rank denotes the no of rows, and the second rank defines no of columns. The following figure
illustrates the two-dimensional array divided into rows and columns.
Two-dimensional Array
In the above example, the value of a two-dimensional array can be accessed by index no of row and
column as [row index, column index]. So, [0, 0] returns the value of the first row and first column
and [1, 1] returns the value from the second row and second column.
Now, let's understand the three-dimensional array. The following declares and initializes three-
dimensional arrays.
As you can see in the above example, [1, 2, 2] of arr3d1 specifies that it will contain one row of two-
dimensional array [2, 2]. arr3d2 specifies dimensions [2, 2, 2], which indicates that it includes two
rows of two-dimensional array of [2, 2]. Thus, the first rank indicates the number of rows of inner
two-dimensional arrays.
In the above example, the four-dimensional array arr4d1 specifies [1, 1, 2, 2], which indicates that it
includes one row of the three-dimensional array.
In the same way, you can declare and initialize five-dimensional, six-dimensional array, and up to
32-dimensional arrays in C#.
A jagged array is an array of array. Jagged arrays store arrays instead of literal values.
A jagged array is initialized with two square brackets [][]. The first bracket specifies the size of an
array, and the second bracket specifies the dimensions of the array which is going to be stored.
In the above example, jArray1 can store up to two single-dimensional arrays. jArray2 can store up to
three two-dimensional, arrays [,] specifies the two-dimensional array.
You can also initialize a jagged array upon declaration like the below.
new int[4]{4, 5, 6, 7}
};
jArray[0][0]; //returns 1
jArray[0][1]; //returns 2
jArray[0][2]; //returns 3
jArray[1][0]; //returns 4
jArray[1][1]; //returns 5
jArray[1][2]; //returns 6
jArray[1][3]; //returns 7
Try it
You can access a jagged array using two for loops, as shown below.
new int[4]{4, 5, 6, 7}
};
The following jagged array stores two-dimensional arrays where the second bracket [,] indicates the
two-dimensional array.
If you add one more bracket then it will be array of array of arry.
Console.WriteLine(intJaggedArray[0][0][0]); // 1
Console.WriteLine(intJaggedArray[0][1][1]); // 5
Console.WriteLine(intJaggedArray[1][0][2]); // 9
Try it
In the above example of a jagged array, three brackets [][][] means an array of array of array.
So, intJaggedArray will contain two elements, which means two arrays. Now, each of these arrays
also contains an array (single-dimension). intJaggedArray[0][0][0] points to the first element of first
inner array. intJaggedArray[1][0][2] points to the third element of the second inner array. The
following figure illustrates this.
Jagged Array
C# .NET includes built-in exception classes for every possible error. The Exception class is the base
class of all the exception classes.
E
xception Classes in .NET
The ApplicationException was recommended to be base class for all your custom exceptions classes
(The custom exeception class should be created if non of the system exception classes can be used
and you need new exception class for business rule violations or for other application related errors).
It was meant to differentiates between exceptions defined by applications versus exceptions defined
by the system. However, Microsoft now recommends to derive custom exception classes from
the Exception class rather than the ApplicationException class .
The following figure shows how the NullReferenceException is thrown in Visual Studio debug
mode when you access a null object property at runtime.
NullRefer
enceException
Built-in Exception Classes
When an error occurs, either the application code or the default handler handles the exception. Learn
how to handle the excetion in the next section.
Exception Handling in C#
Here, you will learn about exception handling in C# using try, catch, and finally blocks.
Exceptions in the application must be handled to prevent crashing of the program and unexpected
result, log exceptions and continue with other functionalities. C# provides built-in support to handle
the exception using try, catch & finally blocks.
Syntax:
try
{
// put the code here that may raise exceptions
}
catch
{
// handle exception here
}
finally
{
// final cleanup code
}
try block: Any suspected code that may raise exceptions should be put inside a try{ } block. During
the execution, if an exception occurs, the flow of the control jumps to the first matching catch block.
catch block: The catch block is an exception handler block where you can perform some action such
as logging and auditing an exception. The catch block takes a parameter of an exception type using
which you can get the details of an exception.
finally block: The finally block will always be executed whether an exception raised or not.
Usually, a finally block should be used to release resources, e.g., to close any stream or file objects
that were opened in the try block.
Example: C# Program
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter a number: ");
To handle the possible exceptions in the above example, wrap the code inside a try block and handle
the exception in the catch block, as shown below.
In the above example, we wrapped this code inside a try block. If an exception occurs inside
a try block, then the program will jump to the catch block. Inside a catch block, we display a
message to instruct the user about his mistake, and in the finally block, we display a message about
what to do after running a program.
Note:
A try block must be followed by catch or finally or both blocks. The try block without
a catch or finally block will give a compile-time error.
Ideally, a catch block should include a parameter of a built-in or custom exception class to get an
error detail. The following includes the Exception type parameter that catches all types of
exceptions.
Exception Filters
You can use multiple catch blocks with the different exception type parameters. This is called
exception filters. Exception filters are useful when you want to handle different types of exceptions
in different ways.
try
{
int num = int.Parse(Console.ReadLine());
}
Try it
In the above example, we have specified multiple catch blocks with different exception types. We
can display an appropriate message to the user, depending upon the error, so the user does not repeat
the same mistake again.
Note:
Multiple catch blocks with the same exception type are not allowed. A catch block with the base
Exception type must be the last block.
ADVERTISEMENT
A parameterless catch block and a catch block with the Exception parameter are not allowed in the
same try-catch statements, because they both do the same thing.
Also, parameterless catch block catch{ } or general catch block catch(Exception ex){ } must be the
last block. The compiler will give an error if you have other catch blocks after
a catch{ } or catch(Exception ex) block.
finally Block
The finally block is an optional block and should come after a try or catch block. The finally block
will always be executed whether or not an exception occurred. The finally block generally used for
cleaning-up code e.g., disposing of unmanaged objects.
try
{
Console.Write("Enter a file name to write: ");
string fileName = Console.ReadLine();
file = new FileInfo(fileName);
file.AppendText("Hello World!")
}
catch(Exception ex)
{
Console.WriteLine("Error occurred: {0}", ex.Message );
}
finally
{
// clean up file object here;
file = null;
}
}
Note:
Multiple finally blocks are not allowed. Also, the finally block cannot have the return, continue, or
break keywords. It doesn't let control to leave the finally block.
Nested try-catch
C# allows nested try-catch blocks. When using nested try-catch blocks, an exception will be caught
in the first matching catch block that follows the try block where an exception occurred.
try
{
try
{
var result = 100/divider;
}
catch
{
Console.WriteLine("Inner catch");
}
}
catch
{
Console.WriteLine("Outer catch");
}
}
Try it
Output:
Inner catch
An inner catch block will be executed in the above example because it is the first catch block that
handles all exception types.
If there isn't an inner catch block that matches with raised exception type, then the control will flow
to the outer catch block until it finds an appropriate exception filter. Consider the following example.
try
{
try
{
var result = 100/divider;
}
catch(NullReferenceException ex)
{
Console.WriteLine("Inner catch");
}
}
catch
{
Console.WriteLine("Outer catch");
}
}
Try it
Output:
Outer catch
In the above example, an exception of type DivideByZeroException will be raised.Because an
inner catch block handles only the NullReferenceTypeException, it will be handle by an
outer catch block.
C# - throw keyword
We have seen in the previous section how to handle exceptions which are automatically raised by
CLR. Here, we will see how to raise an exception manually.
An exception can be raised manually by using the throw keyword. Any type of exceptions which is
derived from Exception class can be raised using the throw keyword.
try
{
PrintStudentName(std);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message );
}
Console.ReadKey();
}
Console.WriteLine(std.StudentName);
}
Try it
Output:
Please notice that throw creates an object of any valid exception type using the new keyword. The
throw keyword cannot be used with any other type which does not derive from the Exception class.
Re-throwing an Exception
You can also re-throw an exception from the catch block to pass on to the caller and let the caller
handle it the way they want. The following example re-throws an exception.
In the above example, an exception occurs in Method2(). The catch block simply throws that
exception using only throw keyword (not throw e). This will be handled in catch block in Method1()
where it again re-throw the same exception and finally it is being handled in the Main() method. The
stack trace of this exception will give you the full detail of where exactly this exception occurred.
If you re-throw an exception using exception parameter then it will not preserve the original
exception and creates a new exception. The following example demonstrates this.
In the above example, exception caught in the Main() method will display stack trace from Method1
and Main method. It will not display Method1 in stack trace as we re-throw exception in Method1()
using throw ex. So, never throw an exception using throw <exception parameter>.
The .Net framework includes ApplicationException class since .Net v1.0. It was designed to use as a
base class for the custom exception class. However, Microsoft now recommends Exception class to
create a custom exception class. You should not throw an ApplicationException exception in your
code, and you should not catch an ApplicationException exception unless you intend to re-throw the
original exception.
For example, create InvalidStudentNameException class in a school application, which does not
allow any special character or numeric value in a name of any of the students.
Example: ApplicationException
class Student
{
public int StudentID { get; set; }
public string StudentName { get; set; }
}
[Serializable]
class InvalidStudentNameException : Exception
{
public InvalidStudentNameException() { }
}
}
Now, you can raise InvalidStudentNameException in your program whenever the name contains
special characters or numbers. Use the throw keyword to raise an exception.
try
{
newStudent = new Student();
newStudent.StudentName = "James007";
ValidateStudent(newStudent);
}
catch(InvalidStudentNameException ex)
{
Console.WriteLine(ex.Message );
}
Console.ReadKey();
}
if (!regex.IsMatch(std.StudentName))
throw new InvalidStudentNameException(std.StudentName);
}
}
Output:
Thus, you can create custom exception classes to differentiate from system exceptions.
C# - Stream
C# includes following standard IO (Input/Output) classes to read/write from different sources like
files, memory, network, isolated storage, etc.
Stream: System.IO.Stream is an abstract class that provides standard methods to transfer bytes (read,
write, etc.) to the source. It is like a wrapper class to transfer bytes. Classes that need to read/write
bytes from a particular source must implement the Stream class.
The following classes inherit Stream class to provide the functionality to Read/Write bytes from a
particular source:
FileStream reads or writes bytes from/to a physical file, whether it is a .txt, .exe, .jpg, or any other
file. FileStream is derived from the Stream class.
BufferedStream: BufferedStream reads or writes bytes from other Streams to improve certain I/O
operations' performance.
StreamReader: StreamReader is a helper class for reading characters from a Stream by converting
bytes into characters using an encoded value. It can be used to read strings (characters) from
different Streams like FileStream, MemoryStream, etc.
BinaryReader: BinaryReader is a helper class for reading primitive datatype from bytes.
The above image shows that FileStream reads bytes from a physical file, and
then StreamReader reads strings by converting those bytes to strings. In the same way,
the StreamWriter takes a string and converts it into bytes and writes to the FileStream, and then
the FileStream writes the bytes to a physical file. So, the FileStream deals with bytes, where
as StreamReader and StreamWriter deals with strings.
Points to Remember :
1. Stream is an abstract class for transfering bytes from different sources. It is base class for all other
class that reads\writes bytes to different sources.
2. FileStream class provides reading and writing functionality of bytes to physical file.
3. Reader & writer classes provides functionality to read bytes from Stream classes (FileStream,
MemoryStream etc) and converts bytes into appropriate encoding.
4. StreamReader provides a helper method to read string from FileStream by converting bytes into
strings. StreamWriter provides a helper method to write string to FileStream by converting strings into
bytes.
C# provides the following classes to work with the File system. They can be used to access
directories, access files, open files for reading or writing, create a new file or move existing files
from one location to another, etc.
File
C# includes static File class to perform I/O operation on physical file system. The static File class
includes various utility method to interact with physical file of any type e.g. binary, text etc.
Use this static File class to perform some quick operation on physical file. It is not recommended to
use File class for multiple operations on multiple files at the same time due to performance reasons.
Use FileInfo class in that scenario.
Method Usage
AppendAllLines Appends lines to a file, and then closes the file. If the specified file does not exist, this
method creates a file, writes the specified lines to the file, and then closes the file.
AppendAllText Opens a file, appends the specified string to the file, and then closes the file. If the file does
not exist, this method creates a file, writes the specified string to the file, then closes the file.
AppendText Creates a StreamWriter that appends UTF-8 encoded text to an existing file, or to a new file
if the specified file does not exist.
Copy Copies an existing file to a new file. Overwriting a file of the same name is not allowed.
Create Creates or overwrites a file in the specified path.
CreateText Creates or opens a file for writing UTF-8 encoded text.
Decrypt Decrypts a file that was encrypted by the current account using the Encrypt method.
Delete Deletes the specified file.
Encrypt Encrypts a file so that only the account used to encrypt the file can decrypt it.
Exists Determines whether the specified file exists.
GetAccessControl Gets a FileSecurity object that encapsulates the access control list (ACL) entries for a
specified file.
Move Moves a specified file to a new location, providing the option to specify a new file name.
Open Opens a FileStream on the specified path with read/write access.
ReadAllBytes Opens a binary file, reads the contents of the file into a byte array, and then closes the file.
ReadAllLines Opens a text file, reads all lines of the file, and then closes the file.
ReadAllText Opens a text file, reads all lines of the file, and then closes the file.
Replace Replaces the contents of a specified file with the contents of another file, deleting the
original file, and creating a backup of the replaced file.
WriteAllBytes Creates a new file, writes the specified byte array to the file, and then closes the file. If the
target file already exists, it is overwritten.
WriteAllLines Creates a new file, writes a collection of strings to the file, and then closes the file.
WriteAllText Creates a new file, writes the specified string to the file, and then closes the file. If the target
file already exists, it is overwritten.
Use AppendAllLines() method to append multiple text lines to the specified file as shown below.
//Opens DummyFile.txt and append lines. If file is not exists then create and open.
File.AppendAllLines(@"C:\DummyFile.txt",
dummyLines.Split(Environment.NewLine.ToCharArray()).ToList<string>());
Append String
Use File.AppendAllText() method to append string to a file in single line of code as shown below.
Example: Append string to a file
//Opens DummyFile.txt and append Text. If file is not exists then create and open.
File.AppendAllText(@"C:\ DummyFile.txt", "This is File testing");
Overwrite Text
Use File.WriteAllText() method to write texts to the file. Please note that it will not append text but
overwrite existing texts.
The following example shows how to perform different operations using static File class.
//Open file and returns FileStream for reading bytes from the file
FileStream fs = File.Open(@"D:\DummyFile.txt", FileMode.OpenOrCreate);
//Open file and return StreamReader for reading string from the file
StreamReader sr = File.OpenText(@"D:\DummyFile.txt");
//Delete file
File.Delete(@"C:\DummyFile.txt");
Thus, it is easy to work with physical file using static File class. However, if you want more
flexibility then use FileInfo class. The same way, use static Directory class to work with physical
directories.
Points to Remember :
1. File is a static class to read\write from physical file with less coding.
2. Static File class provides functionalities such as create, read\write, copy, move, delete and others for
physical files.
3. Static Directory class provides functionalities such as create, copy, move, delete etc for physical
directories with less coding.
4. FileInfo and DirectoryInfo class provides same functionality as static File and Directory class.
C# - FileInfo
Here, you will learn how to use FileInfo class to perform read/write operation on physical files.
The FileInfo class provides the same functionality as the static File class but you have more control
on read/write operations on files by writing code manually for reading or writing bytes from a file.
Property Usage
Extension Gets the string representing the extension part of the file.
IsReadOnly Gets or sets a value that determines if the current file is read only.
LastAccessTime Gets or sets the time the current file or directory was last accessed
LastWriteTime Gets or sets the time when the current file or directory was last written to
Method Usage
AppendText Creates a StreamWriter that appends text to the file represented by this
instance of the FileInfo.
Decrypt Decrypts a file that was encrypted by the current account using the Encrypt
method.
Encrypt Encrypts a file so that only the account used to encrypt the file can decrypt it.
GetAccessControl Gets a FileSecurity object that encapsulates the access control list (ACL)
entries for a specified file.
MoveTo Moves a specified file to a new location, providing the option to specify a
new file name.
Method Usage
OpenText Creates a StreamReader with UTF8 encoding that reads from an existing text
file.
Replace Replaces the contents of a specified file with the file described by the current
FileInfo object, deleting the original file, and creating a backup of the
replaced file.
The following example shows how to read bytes from a file manually and then convert them to a
string using UTF8 encoding:
//define counter to check how much bytes to read. Decrease the counter as you read each byte
int numBytesToRead = (int)fileBytes.Length;
if (n == 0)
break;
numBytesRead += n;
numBytesToRead -= n;
}
//Once you read all the bytes from FileStream, you can convert it into string using UTF8 encoding
string filestring = Encoding.UTF8.GetString(fileBytes);
As you have seen in the above code, you have to write lot of code for reading/writing a string from a
FileSream. The same read/write operation can be done easily using StreamReader and StreamWriter.
The following example shows how StreamReader makes it easy to read strings from a file:
Example: Read file using StreamReader
//Create object of FileInfo for specified path
FileInfo fi = new FileInfo(@"D:\DummyFile.txt");
Notice that fi.Open() has three parameters: The first parameter is FileMode for creating and opening
a file if it does not exist; the second parameter, FileAccess, is to indicate a Read operation; and the
third parameter is to share the file for reading with other users while the file is open.
The following example shows how StreamWriter makes it easy to write strings to a File:
Read and Write operations are not possible on the same FileStream object simultaneously. If you are
already reading from a file, create a separate FileStream object to write to the same file, as shown
below:
Thus you can use FileInfo, StreamReader and StreamWriter class to read/write contents from
physical file.
C# 3.0 (.NET 3.5) introduced Object Initializer Syntax, a new way to initialize an object of a class or
collection. Object initializers allow you to assign values to the fields or properties at the time of
creating an object without invoking a constructor.
class Program
{
static void Main(string[] args)
{
Student std = new Student() { StudentID = 1,
StudentName = "Bill",
Age = 20,
Address = "New York"
};
}
}
Try it
In the above example, Student class is defined without any constructors. In the Main() method, we
have created Student object and assigned values to all or some properties in the curly bracket at the
same time. This is called object initializer syntax.
The compiler compiles the above initializer into something like the following.
Collection can be initialized the same way as class objects using collection initializer syntax.
You can also initialize collections and objects at the same time.
Advantages of Initializers
Initializer syntax makes a code more readable, easy to add elements into the collection.
Useful in multi-threading.
Further Reading
Head First C#: A Learner's Guide to Real-World Programming with C#, XAML, and .NET Third
Edition