Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 261

C# Tutorials

C# is a simple & powerful object-oriented programming language


developed by Microsoft. C# can be used to create various types of
applications, such as web, windows, console applications, or other
types of applications using Visual studio.

These C# tutorials will help you learn the essentials of C#, from the
basic to advance level topics. These tutorials are broken down into
sections, where each section contains a number of related topics that
are packed with easy to understand explanations, real-world
examples, useful tips, informative notes and a "points to remember"
section.

C# Version History
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#:

Version .NET Framework Visual Studio Important Features

C# 1.0 .NET Framework 1.0/1.1 Visual Studio .NET 2002 Basic features

C# 2.0 .NET Framework 2.0 Visual Studio 2005 Generics


Partial types
Anonymous methods
Iterators
Nullable types
Private setters (properties)
Method group conversions (delegates)
Covariance and Contra-variance
Static classes

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
Version .NET Framework Visual Studio Important Features

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# 5.0 .NET Framework 4.5 Visual Studio 2012/2013 Async features


Caller information

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

C# 7.0 .NET Core 2.0 Visual Studio 2017 out variables


Tuples
Discards
Pattern Matching
Local functions
Generalized async return types
more..

C# 8.0 .NET Core 3.0 Visual Studio 2019 Readonly members


Default interface methods
Using declarations
Static local functions
Disposable ref structs
Nullable reference types
more..

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.

Create a New Project in Visual Studio 2017

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.

Example: C# Console Application

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

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

Let's understand the above C# 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 (;).

Compile and Run C# Program


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!!

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.).

Keywords in C# are distributed under the following categories:

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
Modifier keywords

extern

new

override

partial

readonly

sealed

static

unsafe

virtual

volatile

Access Modifier Keywords:


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 are related to program flow.

Statement Keywords

if

else

switch

case

do

for

foreach

in

while

break

continue

default

goto

return

yield

throw

try

catch

finally

checked

unchecked

fixed
Statement Keywords

lock

Method Parameter Keywords


These keywords are applied to the parameters of a method.

Method Parameter Keywords

params

ref

out

Namespace Keywords
These keywords are applied with namespace and related operators.

Namespace Keywords

using

. operator

:: operator

extern alias

ADVERTISEMENT

Operator Keywords
Operator keywords perform miscellaneous actions.

Operator Keywords

as

await
Operator Keywords

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 apply to the current instance or value of an object.

Literal Keywords

null

false

true

value

void
Type Keywords
Type keywords are used for data types.

Type keywords

bool

byte

char

class

decimal

double

enum

float

int

long

sbyte

short

string

struct

uint

ulong

ushort

ADVERTISEMENT

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 are contextual keywords used in LINQ queries.

Query Keywords

From

Where

Select

Group

Into
Query Keywords

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.

Example: Use Keyword as Identifier

public class @class


{
public static int MyProperty { get; set; }
}

@class.MyProperty = 100;

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.

In C#, a class can be defined by using the class keyword.

Example: C# Class

public class MyClass


{
public string myField = string.Empty;

public MyClass()
{
}

public void MyMethod(int parameter1, string parameter2)


{
Console.WriteLine("First Parameter {0}, second parameter {1}",
parameter1,
parameter2);
}

public int MyAutoImplementedProperty { get; set; }

private int myPropertyVar;

public int MyProperty


{
get { return myPropertyVar; }
set { myPropertyVar = value; }
}
}

The following image shows the important building blocks of C# class.


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#. We will learn about it in
the keyword section.

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
A method can be defined using the following template:

{access modifier} {return type} MethodName({parameterType


parameterName})

Example: Method in C#

public void MyMethod(int parameter1, string parameter2)


{
// write your method code here..

}
ADVERTISEMENT

Property
A property can be defined using getters and setters, as shown below:

Example: Property in C#

private int _myPropertyVar;

public int MyProperty


{
get { return _myPropertyVar; }
set { _myPropertyVar = value; }
}

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;

public int MyProperty


{
get {
return _myPropertyVar / 2;
}

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.

The following is an example of an auto-implemented property:

Example: Auto implemented property in C#

public int MyAutoImplementedProperty { get; 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 (.).

In C#, namespace can be defined using the namespace keyword.

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
{

}
}
In the above example, the fully qualified class name
of MyClassExample is CSharpTutorials.Examples.MyClassExample.

C# Variables
In C#, a variable contains a data value of the specific data type.

Syntax
<data type> <variable name> = <value>;

The following declares and initializes a variable of an int type.

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.

The following declares and initializes variables of different data types.

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

The followings are naming conventions for declaring variables in C#:

 Variable names must be unique.


 Variable names can contain letters, digits, and the underscore _ only.
 Variable names must start with a letter.
 Variable names are case-sensitive, num and Num are considered
different names.
 Variable names cannot contain reserved keywords. Must
prefix @ before keyword if want reserve keywords as identifiers.
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.

Example: Cannot assign string to int type variable


int num = "Steve";

Variables can be declared first and initialized later.

Example: Late Initialization


int num;
num = 100;

A variable must be assigned a value before using it, otherwise, C#


will give a compile-time error.

Error: Invalid Assignment


int i;
int j = i; //compile-time error: Use of unassigned local variable 'i'

The value of a variable can be changed anytime after initializing it.

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.

Example: Multiple Variables in a Single Line


int i, j = 10, k = 100;
Try it

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 ;.

Example: Multi-Line Declarations


int i = 0,
j = 10,
k = 100;
Try it
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.

Example: Variable Assignment


int i = 100;

int j = i; // value of j will be 100


Try 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.

C# - var
In C#, variables must be declared with the data type. These are
called explicitly typed variables.

Example: Explicitly Typed Variable

int i = 100;// explicitly typed variable

C# 3.0 introduced var keyword to declare method level variables


without specifying a data type explicitly.

Example: Implicitly Typed Local Variable

var j = 100; // implicitly typed local variable

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.

The following infers the type from an expression.

Example: var from expression

int i = 10;
var j = i + 1; // compiles as int
var can be used to declare any built-in data type or a user-defined
type or an anonymous type variable. The following example shows
C# compiler infers type based on the value:

Example: Implicitly-Typed Variable

static void Main(string[] args)


{
var i = 10;
Console.WriteLine("Type of i is {0}", i.GetType());

var str = "Hello World!!";


Console.WriteLine("Type of str is {0}", str.GetType());

var dbl = 100.50d;


Console.WriteLine("Type of dbl is {0}", dbl.GetType());

var isValid = true;


Console.WriteLine("Type of isValid is {0}", isValid.GetType());

var ano = new { name = "Steve" };


Console.WriteLine("Type of ano is {0}", ano.GetType());

var arr = new[] { 1, 10, 20, 30 };


Console.WriteLine("Type of arr is {0}", arr.GetType());

var file = new FileInfo("MyFile");


Console.WriteLine("Type of file is {0}", file.GetType());

}
Try it

Implicitly-typed variables must be initialized at the time of


declaration; otherwise C# compiler would give an error: Implicitly-
typed variables must be initialized.

var i; // Compile-time error: Implicitly-typed variables must be


initialized
i = 100;

Multiple declarations of var variables in a single statement are not


allowed.
var i = 100, j = 200, k = 300; // Error: cannot declare var variables
in a single statement

//The followings are also valid


var i = 100;
var j = 200;
var k = 300;

var cannot be used for function parameters.

void Display(var param) //Compile-time error


{
Console.Write(param);
}

var can be used in for, and foreach loops.

for(var i = 0; i < 10; i++)


{
Console.WriteLine(i);
}

var can also be used with LINQ queries.

Example: LINQ Query Syntax in C#

// string collection
IList<string> stringList = new List<string>() {
"C# Tutorials",
"VB.NET Tutorials",
"Learn C++",
"MVC Tutorials" ,
"Java"
};

// LINQ Query Syntax


var result = from s in stringList
where s.Contains("Tutorials")
select s;

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.

The following declares and initialized variables of different data


types.

Example: Variables of Different Data Types

string stringVar = "Hello World!!";


int intVar = 100;
float floatVar = 10.2f;
char charVar = 'A';
bool boolVar = true;
Try it

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:

Type Description Range Suffix

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

DateTim Represents date and time 0:00:00am 1/1/01


e to
Type Description Range Suffix

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.

Example: Compile time error

// compile time error: Cannot implicitly convert type 'long' to 'int'.


int i = 21474836470;

The value of unsigned integers, long, float, double, and decimal type
must be suffix by u,l,f,d, and m, respectively.

Example: Value Suffix

uint ui = 100u;
float fl = 10.2f;
long l = 45755452222222l;
ulong ul = 45755452222222ul;
double d = 11452222.555d;
decimal mon = 1000.15m;
Try it
ADVERTISEMENT

Alias vs .NET Type


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.

Alias .NET Type Type

byte System.Byte struct

sbyte System.SByte struct


Alias .NET Type Type

int System.Int32 struct

uint System.UInt32 struct

short System.Int16 struct

ushort System.UInt16 struct

long System.Int64 struct

ulong System.UInt64 struct

float System.Single struct

double System.Double struct

char System.Char struct

bool System.Boolean struct

object System.Object Class

string System.String Class

decimal System.Decimal struct

DateTime System.DateTime struct

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.

Example: Implicit Conversion

int i = 345;
float f = i;

Console.WriteLine(f); //output: 345

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#.

The following is an implicit data type conversion table.

Implicit Conversion From To

sbyte short, int, long, float, double, decimal

byte short, ushort, int, uint, long, ulong, float, double, decimal

short int, long, float, double, or decimal

ushort int, uint, long, ulong, float, double, or decimal

int long, float, double, or decimal.

uint long, ulong, float, double, or decimal

long float, double, or decimal

ulong float, double, or decimal


Implicit Conversion From To

char ushort, int, uint, long, ulong, float, double, or decimal

float Double

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.
The following figure illustrates numeric types in C#.

Numeric 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.

Example: byte, sbyte

byte b1 = 255;
byte b2 = -128;// compile-time error: Constant value '-128' cannot be
converted to a 'byte'
sbyte sb1 = -128;
sbyte sb2 = 127;

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.

Example: short, ushort

short s1 = -32768;
short s2 = 32767;
short s3 = 35000;//Compile-time error: Constant value '35000' cannot
be converted to a 'short'

ushort us1 = 65535;


ushort us2 = -32000; //Compile-time error: Constant value '-32000'
cannot be converted to a 'ushort'

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.

Example: int, uint


int i = -2147483648;
int j = 2147483647;
int k = 4294967295; //Compile-time error: Cannot implicitly convert
type 'uint' to 'int'.

uint ui1 = 4294967295;


uint ui2 =-1; //Compile-time error: Constant value '-1' cannot be
converted to a 'uint'

Console.WriteLine(Int32.MaxValue);//2147483647
Console.WriteLine(Int32.MinValue);//-2147483648
Console.WriteLine(UInt32.MaxValue);//4294967295
Console.WriteLine(UInt32.MinValue);//0

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);

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.

The ulong type stores positive numbers from 0 to


18,446,744,073,709,551,615. If a number is suffixed by UL, Ul, uL,
ul, LU, Lu, lU, or lu, its type is ulong. The uint keyword is an alias
of UInt64 struct in .NET.

Example: long, ulong

long l1 = -9223372036854775808;
long l2 = 9223372036854775807;
ulong ul1 = 18223372036854775808ul;
ulong ul2 = 18223372036854775808UL;

Console.WriteLine(Int64.MaxValue);//9223372036854775807
Console.WriteLine(Int64.MinValue);//-9223372036854775808
Console.WriteLine(UInt64.MaxValue);//18446744073709551615
Console.WriteLine(UInt64.MinValue);//0
Try it

Floating Point Types


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.

Use f or F suffix with literal to make it float type.

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.

Use d or D suffix with literal to make it double type.

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.

Use m or M suffix with literal to make it decimal type.

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

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.

Example: String Literals

"S"
"String"
"This is a string."

C# provides the String data type to store string literals. A variable of


the string type can be declared and assign string literal, as shown
below.

Example: String Type Variables

string ch = "S";
string word = "String";
string text = "This is a string.";
Try it

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.

Example: String and string

string str1 = "Hello"; // uses string keyword

String str2 = "Hello"; // uses System.String class


Try it
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.

Example: String as char Array

char[] chars = {'H','e','l','l','o'};

string str1 = new string(chars);


String str2 = new String(chars);

foreach (char c in str1)


{
Console.WriteLine(c);
}
Try it

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.

Example: Invalid String

string text = "This is a "string" in C#.";

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.

Example: Escape Char \

string text = "This is a \"string\" in C#.";


string str = "xyzdef\\rabc";
string path = "\\\\mypc\\ shared\\project";
Try it

However, it will be very tedious to prefix \ for every special


character. Prefixing the string with an @ indicates that it should be
treated as a literal and should not escape any character.
Example: Escape Sequence

string str = @"xyzdef\rabc";


string path = @"\\mypc\shared\project";
string email = @"test@test.com";
Try it

Use @ and \ to declare a multi-line string.

Example: Multi-line String

string str = @"this is a \


multi line \
string";
Try it

Please note that you must use a backslash to allow " in a string. @ is
only for special characters in C#.

string text = @"This is a "string." in C#."; // error


string text = @"This is a \"string\" in C#."; // error
string text = "This is a \"string\" in C#."; // valid
ADVERTISEMENT

String Concatenation
Multiple strings can be concatenated with + operator.

Example: String Concatenation


string name = "Mr." + "James " + "Bond" + ", Code: 007";

string firstName = "James";


string lastName = "Bond";
string code = "007";

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.

C# 6 includes a special character $ to identify an interpolated string.


An interpolated string is a mixture of static string and string variable
where string variables should be in {} brackets.

Example: String Interpolation

string firstName = "James";


string lastName = "Bond";
string code = "007";

string fullName = $"Mr. {firstName} {lastName}, Code: {code}";


Try it

In the above example of interpolation, $ indicates the interpolated


string, and {} includes string variable to be incorporated with a
string.

Use two braces, "{{" or "}}" to include { or } in a string.

Working with Date and Time in C#


C# includes DateTime struct to work with dates and times.

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.

Example: Create DateTime Object

DateTime dt = new DateTime(); // assigns default value 01/01/0001


00:00:00
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.

Example: Set Date & Time

//assigns default value 01/01/0001 00:00:00


DateTime dt1 = new DateTime();

//assigns year, month, day


DateTime dt2 = new DateTime(2015, 12, 31);

//assigns year, month, day, hour, min, seconds


DateTime dt3 = new DateTime(2015, 12, 31, 5, 10, 20);

//assigns year, month, day, hour, min, seconds, UTC timezone


DateTime dt4 = new DateTime(2015, 12, 31, 5, 10, 20,
DateTimeKind.Utc);
Try it

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.

Example: Invalid Date

DateTime dt = new DateTime(2015, 12, 32); //throws exception: day out


of range

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

DateTime Static Fields


The DateTime struct includes static fields, properties, and methods.
The following example demonstrates important static fields and
properties.

Example: Static Fields

DateTime currentDateTime = DateTime.Now; //returns current date and


time
DateTime todaysDate = DateTime.Today; // returns today's date
DateTime currentDateTimeUTC = DateTime.UtcNow;// returns current UTC
date and time

DateTime maxDateTimeValue = DateTime.MaxValue; // returns max value of


DateTime
DateTime minDateTimeValue = DateTime.MinValue; // returns min value of
DateTime
Try it

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);

TimeSpan ts = new TimeSpan(25,20,55);

DateTime newDate = dt.Add(ts);

Console.WriteLine(newDate);//1/1/2016 1:20:55 AM
Try it
Subtraction of two dates results in TimeSpan.

Example: Subtract Dates

DateTime dt1 = new DateTime(2015, 12, 31);


DateTime dt2 = new DateTime(2016, 2, 2);
TimeSpan result = dt2.Subtract(dt1);//33.00:00:00
Try it
ADVERTISEMENT

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);

Console.WriteLine(dt2 + time); // 1/10/2017 10:36:10 AM


Console.WriteLine(dt2 - dt1); //377.05:10:20
Console.WriteLine(dt1 == dt2); //False
Console.WriteLine(dt1 != dt2); //True
Console.WriteLine(dt1 > dt2); //False
Console.WriteLine(dt1 < dt2); //True
Console.WriteLine(dt1 >= dt2); //False
Console.WriteLine(dt1 <= dt2);//True
Try it

Convert DateTime to String


The DateTime struct includes the following methods to convert a date
and time to string.

Method Description

ToString Converts a DateTime value to a string in the specified format of the current culture.

ToShortDateString Converts a DateTime value to a short date string (M/d/yyyy pattern) in the current culture.
Method Description

ToShortTimeString Converts a DateTime value to a short time string (h:mm:ss pattern) in the current culture.

ToLongDateString Converts a DateTime value to a long date string (dddd, MMMM d, yyyy pattern) in the current culture.

ToLongTimeString Converts a DateTime value to a long time string (h:mm:ss tt pattern) in the current culture.

The following example demonstrates converting DateTime to strings


in different formats.

Example: DateTime to String

var dt = DateTime.Now;

Console.WriteLine("Date String Current Culture: " + dt.ToString("d"));


Console.WriteLine("MM/dd/yyyy Format: " + dt.ToString("MM/dd/yyyy"));
Console.WriteLine("dddd, dd MMMM yyyy Format: " + dt.ToString("dddd,
dd MMMM yyyy"));
Console.WriteLine("MM/dd/yyyy h:mm tt Format: " +
dt.ToString("MM/dd/yyyy h:mm tt"));
Console.WriteLine("MMMM dd Format:" + dt.ToString("MMMM dd"));
Console.WriteLine("HH:mm:ss Format: " + dt.ToString("HH:mm:ss"));
Console.WriteLine("hh:mm tt Format: " + dt.ToString("hh:mm tt"));
Console.WriteLine("Short Date String: " + dt.ToShortDateString());
Console.WriteLine("Long Date String: " + dt.ToLongDateString());
Console.WriteLine("Short Time String: " + dt.ToShortTimeString());
Console.WriteLine("Long Time String: " + dt.ToLongTimeString());
Try it

Convert String to DateTime


A valid date and time string can be converted to a DateTime object
using Parse(), ParseExact() , TryParse()  and TryParseExact()  methods
.

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;

var isValidDate = DateTime.TryParse(str, out dt);

if(isValidDate)
Console.WriteLine(dt);
else
Console.WriteLine($"{str} is not a valid date string");

C# - Struct

Updated on: June 25, 2020

In C#, struct is the value type data type that represents data


structures. It can contain a parameterized constructor, static
constructor, constants, fields, methods, properties, indexers,
operators, events, and nested types.

struct can be used to hold small data values that do not require


inheritance, e.g. coordinate points, key-value pairs, and complex
data structure.

Structure Declaration
A structure is declared using struct keyword. The default modifier is
internal for the struct and its members.

The following example declares a structure Coordinate for the graph.

Example: Structure

struct Coordinate
{
public int x;
public int y;
}
A struct object can be created with or without the new operator,
same as primitive type variables.

Example: Create Structure

struct Coordinate
{
public int x;
public int y;
}

Coordinate point = new Coordinate();


Console.WriteLine(point.x); //output: 0
Console.WriteLine(point.y); //output: 0
Try it

Above, an object of the Coordinate structure is created using


the new keyword. It calls the default parameterless constructor of
the struct, which initializes all the members to their default value of
the specified data type.

If you declare a variable of struct type without using new keyword, it


does not call any constructor, so all the members remain unassigned.
Therefore, you must assign values to each member before accessing
them, otherwise, it will give a compile-time error.

Example: Create Structure Without new Keyword

struct Coordinate
{
public int x;
public int y;
}

Coordinate point;
Console.Write(point.x); // Compile time error

point.x = 10;
point.y = 20;
Console.Write(point.x); //output: 10
Console.Write(point.y); //output: 20
Try it
Constructors in Structure
A struct cannot contain a parameterless constructor. It can only
contain parameterized constructors or a static constructor.

Example: Parameterized Constructor in Struct

struct Coordinate
{
public int x;
public int y;

public Coordinate(int x, int y)


{
this.x = x;
this.y = y;
}
}

Coordinate point = new Coordinate(10, 20);

Console.WriteLine(point.x); //output: 10
Console.WriteLine(point.y); //output: 20
Try it

You must include all the members of the struct in the parameterized


constructor and assign parameters to members; otherwise C#
compiler will give a compile-time error if any member remains
unassigned.
ADVERTISEMENT

Methods and Properties in Structure


A struct can contain properties, auto-implemented properties,
methods, etc., same as classes.

Example: Methods and Properties in Struct

struct Coordinate
{
public int x { get; set; }
public int y { get; set; }

public void SetOrigin()


{
this.x = 0;
this.y = 0;
}
}

Coordinate point = Coordinate();


point.SetOrigin();

Console.WriteLine(point.x); //output: 0
Console.WriteLine(point.y); //output: 0
Try it

The following struct includes the static method.

Example: Static Constructor in Struct

struct Coordinate
{
public int x;
public int y;

public Coordinate(int x, int y)


{
this.x = x;
this.y = y;
}

public static Coordinate GetOrigin()


{
return new Coordinate();
}
}

Coordinate point = Coordinate.GetOrigin();

Console.WriteLine(point.x); //output: 0
Console.WriteLine(point.y); //output: 0
Try it
Events in Structure
A struct can contain events to notify subscribers about some action.
The following struct contains an event.

Example: Event in Structure

struct Coordinate
{
private int _x, _y;

public int x
{
get{
return _x;
}

set{
_x = value;
CoordinatesChanged(_x);
}
}

public int y
{
get{
return _y;
}

set{
_y = value;
CoordinatesChanged(_y);
}
}

public event Action<int> CoordinatesChanged;


}

The above structure contains CoordinatesChanged event, which will be


raised when x or y coordinate changes. The following example
demonstrates the handling of the CoordinatesChanged event.

Example: Handle Structure Events


class Program
{
static void Main(string[] args)
{

Coordinate point = new Coordinate();

point.CoordinatesChanged += StructEventHandler;
point.x = 10;
point.y = 20;
}

static void StructEventHandler(int point)


{
Console.WriteLine("Coordinate changed to {0}", point);
}
}
Try it

struct is a value type, so it is faster than a class object. Use struct


whenever you want to just store the data. Generally, structs are
good for game programming. However, it is easier to transfer a class
object than a struct. So do not use struct when you are passing data
across the wire or to other classes.

Summary
 struct can include constructors, constants, fields, methods, properties,
indexers, operators, events & nested types.
 struct cannot include a parameterless constructor or a destructor.
 struct can implement interfaces, same as class.
 struct cannot inherit another structure or class, and it cannot be the base
of a class.
 struct members cannot be specified as abstract, sealed, virtual, or
protected.

C# Enumerations Type - Enum


In C#, an enum (or enumeration type) is used to assign constant
names to a group of numeric integer values. It makes constant
values more readable, for example, WeekDays.Monday is more
readable then number 0 when referring to the day in a week.

An enum is defined using the enum keyword, directly inside a


namespace, class, or structure. All the constant names can be
declared inside the curly brackets and separated by a comma. The
following defines an enum for the weekdays.

Example: Define an Enum

enum WeekDays
{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}

Above, the WeekDays enum declares members in each line separated


by a comma.

Enum Values
If values are not assigned to enum members, then the compiler will
assign integer values to each member starting with zero by default.
The first member of an enum will be 0, and the value of each
successive enum member is increased by 1.

Example: Default Enum Values

enum WeekDays
{
Monday, // 0
Tuesday, // 1
Wednesday, // 2
Thursday, // 3
Friday, // 4
Saturday, // 5
Sunday // 6
}
You can assign different values to enum member. A change in the
default value of an enum member will automatically assign
incremental values to the other members sequentially.

Example: Assign Values to Enum Members

enum Categories
{
Electronics, // 0
Food, // 1
Automotive = 6, // 6
Arts, // 7
BeautyCare, // 8
Fashion // 9
}

You can even assign different values to each member.

Example: Assign Values to Enum Members

enum Categories
{
Electronics = 1,
Food = 5,
Automotive = 6,
Arts = 10,
BeautyCare = 11,
Fashion = 15,
WomanFashion = 15
}

The enum can be of any numeric data type such as byte, sbyte,
short, ushort, int, uint, long, or ulong. However, an enum cannot be
a string type.

Specify the type after enum name as : type. The following defines
the byte enum.

Example: byte Enum

enum Categories: byte


{
Electronics = 1,
Food = 5,
Automotive = 6,
Arts = 10,
BeautyCare = 11,
Fashion = 15
}

Access an Enum
An enum can be accessed using the dot syntax: enum.member

Example: Access Enum

enum WeekDays
{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}

Console.WriteLine(WeekDays.Monday); // Monday
Console.WriteLine(WeekDays.Tuesday); // Tuesday
Console.WriteLine(WeekDays.Wednesday); // Wednesday
Console.WriteLine(WeekDays.Thursday); // Thursday
Console.WriteLine(WeekDays.Friday); // Friday
Console.WriteLine(WeekDays.Saturday); // Saturday
Console.WriteLine(WeekDays.Sunday); // Sunday

Conversion
Explicit casting is required to convert from an enum type to its
underlying integral type.

Example: Enum Conversion

enum WeekDays
{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}

Console.WriteLine(WeekDays.Friday); //output: Friday


int day = (int) WeekDays.Friday; // enum to int conversion
Console.WriteLine(day); //output: 4

var wd = (WeekDays) 5; // int to enum conversion


Console.WriteLine(wd);//output: Saturday
Try it

enum is an abstract class.

C# - StringBuilder

Updated on: June 26, 2020

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

To solve this problem, C# introduced the StringBuilder in


the System.Text  namespace. The StringBuilder doesn't create a new
object in the memory but dynamically expands memory to
accommodate the modified string.

Memory Allocation for StringBuilder


Object
Creating a StringBuilder 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

StringBuilder sb = new StringBuilder(); //string will be appended


later
//or
StringBuilder sb = new StringBuilder("Hello World!");

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.

Example: StringBuilder Iteration

StringBuilder sb = new StringBuilder("Hello World!");

for(int i = 0; i < sb.Length; i++)


Console.Write(sb[i]); // output: Hello World!
Try it
Retrieve String from StringBuilder
The StringBuilder is not the string. Use the ToString() method to
retrieve a string from the StringBuilder object.

Example: Retrieve String from StringBuilder

StringBuilder sb = new StringBuilder("Hello World!");

var greet = sb.ToString(); //returns "Hello World!"


ADVERTISEMENT

Add/Append String to StringBuilder


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.

Example: Adding or Appending Strings in StringBuilder

StringBuilder sb = new StringBuilder();


sb.Append("Hello ");
sb.AppendLine("World!");
sb.AppendLine("Hello C#");
Console.WriteLine(sb);
Try it

Output:

Hello World!

Hello C#.

Append Formated String to StringBuilder


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);

Console.WriteLine(sbAmout);//output: Your total amount is $ 25.00


Try it

Insert String into StringBuilder


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#");

Console.WriteLine(sb); //output: Hello C# World!


Try it

Remove String in StringBuilder


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);

Console.WriteLine(sb); //output: Hello


Try it

Replace String in StringBuilder


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#");

Console.WriteLine(sb);//output: Hello C#!


Try it

 Points to Remember :

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.

C# - Anonymous Type

Updated on: May 2, 2020

In C#, an anonymous type is a type (class) without any name that


can contain public read-only properties only. It cannot contain other
members, such as fields, methods, events, etc.

You create an anonymous type using the new operator with an object


initializer syntax. The implicitly typed variable- var is used to hold
the reference of anonymous types.

The following example demonstrates creating an anonymous type


variable student that contains three properties named Id, FirstName,
and LastName.

Example: Anonymous Type

var student = new { Id = 1, FirstName = "James", LastName = "Bond" };


The properties of anonymous types are read-only and cannot be
initialized with a null, anonymous function, or a pointer type. The
properties can be accessed using dot (.) notation, same as object
properties. However, you cannot change the values of properties as
they are read-only.

Example: Access Anonymous Type

var student = new { Id = 1, FirstName = "James", LastName = "Bond" };


Console.WriteLine(student.Id); //output: 1
Console.WriteLine(student.FirstName); //output: James
Console.WriteLine(student.LastName); //output: Bond

student.Id = 2;//Error: cannot chage value


student.FirstName = "Steve";//Error: cannot chage value
Try it

An anonymous type's property can include another anonymous type.

Example: Nested Anonymous Type

var student = new {


Id = 1,
FirstName = "James",
LastName = "Bond",
Address = new { Id = 1, City = "London", Country =
"UK" }
};

You can create an array of anonymous types also.

Example: Array of Anonymous Types

var students = new[] {


new { Id = 1, FirstName = "James", LastName = "Bond" },
new { Id = 2, FirstName = "Steve", LastName = "Jobs" },
new { Id = 3, FirstName = "Bill", LastName = "Gates" }
};

An anonymous type will always be local to the method where it is


defined. It cannot be returned from the method. However, an
anonymous type can be passed to the method as object type
parameter, but it is not recommended. If you need to pass it to
another method, then use struct or class instead of an anonymous
type.

Mostly, anonymous types are created using the Select clause of a


LINQ queries to return a subset of the properties from each object in
the collection.

Example: LINQ Query returns an Anonymous Type

class Program
{
static void Main(string[] args)
{
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", age =
18 },
new Student() { StudentID = 2, StudentName = "Steve", age
= 21 },
new Student() { StudentID = 3, StudentName = "Bill", age
= 18 },
new Student() { StudentID = 4, StudentName = "Ram" , age =
20 },
new Student() { StudentID = 5, StudentName = "Ron" , age =
21 }
};

var students = from s in studentList


select new { Id = s.StudentID, Name =
s.StudentName };

foreach(var stud in students)


Console.WriteLine(stud.Id + "-" + stud.Name);
}
}

public class Student


{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int age { get; set; }
}
Try it

Output:
1-John

2-Steve

3-Bill

4-Ram

5-Ron

In the above example, a select clause in the LINQ query selects


only StudentID and StudentName properties and renames it
to Id and Name, respectively. Thus, it is useful in saving memory and
unnecessary code. The query result collection includes
only StudentID and StudentName properties, as shown in the following
debug view.

Visual Studio supports IntelliSense for anonymous types, as shown


below.

An
onymous Type Intellisense Support in Visual Studio

Internally, all the anonymous types are directly derived from


the System.Object class. The compiler generates a class with some
auto-generated name and applies the appropriate type to each
property based on the value expression. Although your code cannot
access it. Use GetType() method to see the name.
Example: Internal Name of an Anonymous Type

static void Main(string[] args)


{
var student = new { Id = 1, FirstName = "James", LastName = "Bond"
};
Console.WriteLine(student.GetType().ToString());
}

C# - Dynamic Types
C# 4.0 (.NET 4.5) introduced a new type called dynamic that avoids
compile-time type checking. A dynamic type escapes type checking at
compile-time; instead, it resolves type at run time.

A dynamic type variables are defined using the dynamic keyword.

Example: dynamic Variable

dynamic MyDynamicVar = 1;

The compiler compiles dynamic types into object types in most cases.
However, the actual type of a dynamic type variable would be
resolved at run-time.

Example: dynamic Type at run-time

dynamic MyDynamicVar = 1;

Console.WriteLine(MyDynamicVar.GetType());
Output:

System.Int32

Dynamic types change types at run-time based on the assigned


value. The following example shows how a dynamic variable changes
type based on assigned value.

Example: dynamic
static void Main(string[] args)
{
dynamic MyDynamicVar = 100;
Console.WriteLine("Value: {0}, Type: {1}", MyDynamicVar,
MyDynamicVar.GetType());

MyDynamicVar = "Hello World!!";


Console.WriteLine("Value: {0}, Type: {1}", MyDynamicVar,
MyDynamicVar.GetType());

MyDynamicVar = true;
Console.WriteLine("Value: {0}, Type: {1}", MyDynamicVar,
MyDynamicVar.GetType());

MyDynamicVar = DateTime.Now;
Console.WriteLine("Value: {0}, Type: {1}", MyDynamicVar,
MyDynamicVar.GetType());
}
Try it

Output:

Value: 100, Type: System.Int32

Value: Hello World!!, Type: System.String

Value: True, Type: System.Boolean

Value: 01-01-2014, Type: System.DateTime

The dynamic type variables is converted to other types implicitly.

Example: dynamic Type Conversion

dynamic d1 = 100;
int i = d1;

d1 = "Hello";
string greet = d1;

d1 = DateTime.Now;
DateTime dt = d1;

Methods and Parameters


If you assign a class object to the dynamic type, then the compiler
would not check for correct methods and properties name of a
dynamic type that holds the custom class object. Consider the
following example.

Example: Calling Methods

class Program
{
static void Main(string[] args)
{
dynamic stud = new Student();

stud.DisplayStudentInfo(1, "Bill");// run-time error, no


compile-time error
stud.DisplayStudentInfo("1");// run-time error, no compile-
time error
stud.FakeMethod();// run-time error, no compile-time error
}
}

public class Student


{
public void DisplayStudentInfo(int id)
{
}
}
Try it

In the above example, the C# compiler does not check for the
number of parameters, parameters type, or non-existent. It validates
these things at run-time, and if it is not valid, then throws a run-time
exception. Note that Visual Studio IntelliSense is not supported for
the dynamic types. Note that Visual Studio IntelliSense is not
supported for the dynamic types.

The dynamic language runtime (DLR) API provides the infrastructure


that supports the dynamic type in C#.
C# - Nullable Types
As you know, a value type cannot be assigned a null value. For
example, int i = null will give you a compile time error.

C# 2.0 introduced nullable types that allow you to assign null to


value type variables. You can declare nullable types
using Nullable<t> where T is a type.

Example: Nullable type

Nullable<int> i = null;

A nullable type can represent the correct range of values for its
underlying value type, plus an additional null value. For example,
Nullable<int> can be assigned any value from -2147483648 to
2147483647, or a null value.

The Nullable types are instances of System.Nullable<T> struct. Think


it as something like the following structure.

Example: Nullable struct

[Serializable]
public struct Nullable<T> where T : struct
{
public bool HasValue { get; }

public T Value { get; }

// other implementation
}

A nullable of type int is the same as an ordinary int plus a flag that


says whether the int has a value or not (is null or not). All the rest is
compiler magic that treats "null" as a valid value.

Example: HasValue

static void Main(string[] args)


{
Nullable<int> i = null;
if (i.HasValue)
Console.WriteLine(i.Value); // or Console.WriteLine(i)
else
Console.WriteLine("Null");
}
Try it

Output:

Null

The HasValue returns true if the object has been assigned a value; if


it has not been assigned any value or has been assigned a null value,
it will return false.

Accessing the value using NullableType.value will throw a runtime


exception if nullable type is null or not assigned any value. For
example, i.Value will throw an exception if i is null:

Invalid
use of Nullable Type

Use the GetValueOrDefault() method to get an actual value if it is not


null and the default value if it is null. For example:

Example: GetValueOrDefault()

static void Main(string[] args)


{
Nullable<int> i = null;

Console.WriteLine(i.GetValueOrDefault());
}
Try it
Shorthand Syntax for Nullable Types
You can use the '?' operator to shorthand the syntax e.g. int?, long?
instead of using Nullable<T>.

Example: Shorthand syntax for Nullable types

int? i = null;
double? D = null;

?? Operator
Use the '??' operator to assign a nullable type to a non-nullable type.

Example: ?? operator with Nullable Type

int? i = null;

int j = i ?? 0;

Console.WriteLine(j);
Try it

Output:

In the above example, i is a nullable int and if you assign it to the


non-nullable int j then it will throw a runtime exception if i is null. So
to mitigate the risk of an exception, we have used the '??' operator
to specify that if i is null then assign 0 to j.
ADVERTISEMENT

Assignment Rules
A nullable type has the same assignment rules as a value type. It
must be assigned a value before using it if nullable types are
declared in a function as local variables. If it is a field of any class
then it will have a null value by default.
For example, the following nullable of int type is declared and used
without assigning any value. The compiler will give "Use of
unassigned local variable 'i'" error:

Unassigned
nullable type-error

In the following example, a nullable of int type is a field of the class,


so it will not give any error.

Example: Nullable type as Class Field

class MyClass
{
public Nullable<int> i;
}
class Program
{
static void Main(string[] args)
{
MyClass mycls = new MyClass();

if(mycls.i == null)
Console.WriteLine("Null");
}
}
Try it

Output:

Null
Nullable Helper Class
Null is considered to be less than any value. So comparison operators
won't work against null. Consider the following example where i is
neither less than j, greater than j nor equal to j:

Example: Nullable Type Comparison

static void Main(string[] args)


{
int? i = null;
int j = 10;

if (i < j)
Console.WriteLine("i < j");
else if( i > 10)
Console.WriteLine("i > j");
else if( i == 10)
Console.WriteLine("i == j");
else
Console.WriteLine("Could not compare");
}
Try it

Output:

Could not compare

Nullable static class is a helper class for Nullable types. It provides a


compare method to compare nullable types. It also has a
GetUnderlyingType method that returns the underlying type
argument of nullable types.

Example: Helper Class

static void Main(string[] args)


{
int? i = null;
int j = 10;

if (Nullable.Compare<int>(i, j) < 0)
Console.WriteLine("i < j");
else if (Nullable.Compare<int>(i, j) > 0)
Console.WriteLine("i > j");
else
Console.WriteLine("i = j");
}

Try it

Output:

i < j

Characteristics of Nullable Types


1. Nullable types can only be used with value types.
2. The Value property will throw an InvalidOperationException if value is null;
otherwise it will return the value.
3. The HasValue property returns true if the variable contains a value, or false if
it is null.
4. You can only use == and != operators with a nullable type. For other
comparison use the Nullable static class.
5. Nested nullable types are not allowed. Nullable<Nullable<int>> i; will give a
compile time error.

 Points to Remember :

1. Nullable<T> type allows assignment of null to value types.


2. ? operator is a shorthand syntax for Nullable types.
3. Use value property to get the value of nullable type.
4. Use HasValue property to check whether value is assigned to nullable
type or not.
5. Static Nullable class is a helper class to compare nullable types.

Value Type and Reference Type


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.

For example, consider integer variable int i = 100;

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':

Memory Allocation of Value Type Variable

The following data types are all of value type:

 bool
 byte
 char
 decimal
 double
 enum
 float
 int
 long
 sbyte
 short
 struct
 uint
 ulong
 ushort

Passing Value Type Variables


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.

Example: Passing Value Type Variables

static void ChangeValue(int x)


{
x = 200;

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.

For example, consider the following string variable:


string s = "Hello World!!";

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

Passing Reference Type Variables


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.

Example: Passing Reference Type Variable

static void ChangeReferenceType(Student std2)


{
std2.StudentName = "Steve";
}

static void Main(string[] args)


{
Student std1 = new Student();
std1.StudentName = "Bill";

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.

Example: Passing String

static void ChangeReferenceType(string name)


{
name = "Steve";
}

static void Main(string[] args)


{
string name = "Bill";

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.

Null Reference Type


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.)

Example: Invalid Interface with Access Modifiers

interface IFile
{
protected void ReadFile(); //compile-time error
private void WriteFile(string text);//compile-time error
}
An interface can only contain declarations but not implementations.
The following will give a compile-time error.

Example: Invalid Interface with Implementation

interface IFile
{
void ReadFile();
void WriteFile(string text){
Console.Write(text); //error: cannot implement method
}
}

Implementing an Interface
A class or a Struct can implement one or more interfaces using colon
(:).

Syntax: <Class or Struct Name> : <Interface Name>

For example, the following class implements the IFile interface


implicitly.

Example: Interface Implementation

interface IFile
{
void ReadFile();
void WriteFile(string text);
}

class FileInfo : IFile


{
public void ReadFile()
{
Console.WriteLine("Reading File");
}

public void WriteFile(string text)


{
Console.WriteLine("Writing to file");
}
}
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.

Example: Interface Implementation

public class Program


{
public static void Main()
{
IFile file1 = new FileInfo();
FileInfo file2 = new FileInfo();

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
An interface can be implemented explicitly
using <InterfaceName>.<MemberName>. Explicit implementation is
useful when class is implementing multiple interfaces; thereby, it is
more readable and eliminates the confusion. It is also useful if
interfaces have the same method name coincidently.

 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);
}

class FileInfo : IFile


{
void IFile.ReadFile()
{
Console.WriteLine("Reading File");
}

void IFile.WriteFile(string text)


{
Console.WriteLine("Writing to file");
}
}

When you implement an interface explicitly, you can access interface


members only through the instance of an interface type.

Example: Explicit Implementation

interface IFile
{
void ReadFile();
void WriteFile(string text);
}

class FileInfo : IFile


{
void IFile.ReadFile()
{
Console.WriteLine("Reading File");
}
void IFile.WriteFile(string text)
{
Console.WriteLine("Writing to file");
}

public void Search(string text)


{
Console.WriteLine("Searching in file");
}
}

public class Program


{
public static void Main()
{
IFile file1 = new FileInfo();
FileInfo file2 = new FileInfo();

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.

Implementing Multiple Interfaces


A class or struct can implement multiple interfaces. It must provide
the implementation of all the members of all interfaces.

Example: Implement Multiple Interfaces

interface IFile
{
void ReadFile();
}

interface IBinaryFile
{
void OpenBinaryFile();
void ReadFile();
}

class FileInfo : IFile, IBinaryFile


{
void IFile.ReadFile()
{
Console.WriteLine("Reading Text File");
}

void IBinaryFile.OpenBinaryFile()
{
Console.WriteLine("Opening Binary File");
}

void IBinaryFile.ReadFile()
{
Console.WriteLine("Reading Binary File");
}

public void Search(string text)


{
Console.WriteLine("Searching in File");
}
}

public class Program


{
public static void Main()
{
IFile file1 = new FileInfo();
IBinaryFile file2 = new FileInfo();
FileInfo file3 = new FileInfo();

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.

The following example demonstrates the + operator in C#.

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.

Example: + Operator with Strings

string greet1 = "Hello " + "World!";


string greet2 = greeting + name;
Try it

 Note:

There are two types of operators in C#, Unary operators and Binary operators.
Unary operators act on single operand, whereas binary operators act on two
operands (left-hand side and right-hand side operand of an operator).

C# includes the following categories of operators:

 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.

Operator Name Description Example

+ Addition Computes the sum of left and right operands. int x = 5 + 5; Try it
Operator Name Description Example

- Subtraction Subtract the right operand from the left operand int x = 5 - 1; Try it

* Multiplication Multiply left and right operand int x = 5 * 1; Try it

/ Division Divides the left operand by the right operand int x = 10 / 2; Try it

% Reminder Computes the remainder after dividing its left operand by int x = 5 % 2; Try it
its right operand

++ Unary increment Unary increment ++ operator increases its operand by 1 x++ Try it

-- Unary decrement Unary decrement -- operator decreases its operand by 1 x-- Try it

+ Unary plus Returns the value of operand +5 Try it

- Unary minus Computes the numeric negation of its operand. -5 Try it

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 Exampl
r Name Description e

= Assignment Assigns its right had value to its left-hand variable, property or indexer. x = 10; Try
it

x op= y Compound assignment Short form of x =x op y where op = any arithmetic, Boolean logical, and x += 5; Try
bitwise operator. it

??= Null-coalescing C# 8 onwards, ??= assigns value of the right operand only if the left operand x ??= 5; Try
assignment is null it
Comparison Operators
Comparison operators compre two numeric operands and returns
true or false.

Operator Description Example

< Returns true if the right operand is less than the left operand x < y; Try it

> Returns true if the right operand is greater than the left operand x > y; Try it

<= Returns true if the right operand is less than or equal to the left operand x <= y Try it

>= Returns true if the right operand is greater than or equal to the left operand x >= y; Try it

ADVERTISEMENT

Equality Operators
The equality operator checks whether the two operands are equal or
not.

Operator Description Example

== Returns true if operands are equal otherwise false. x == y; Try it

!= Returns true if operands are not equal otherwise false. x != y; Try it

Boolean Logical Operators


The Boolean logical operators perform a logical operation on bool
operands.

Operato
r Description Example

! Reverses the bool result of bool expression. Returns false if result is true and returns true if result is !false Try
false. it

&& Computes the logical AND of its bool operands. Returns true both operands are true, otherwise x && y; Try
returns false. it
Operato
r Description Example

|| Computes the logical OR of its bool operands. Returns true when any one operand is true. x || y; Try
it

Operator Evaluation & Precedence


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, nameof, delegate, Primary
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
Operators Category

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 >>= y, x ??= y, => Assignment and lambda


declaration

The following example demonstrates operator precedence:

Example: Operator Precedence

int a = 5 + 3 * 3;
int b = 5 + 3 * 3 / 2;
int c = (5 + 3) * 3 / 2;
int d = (3 * 3) * (3 / 3 + 5);

C# - if, else if, else Statements

Updated on: June 24, 2020

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.

C# includes the following flavors of if statements:

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.

Example: Wrong if Statement

int i = 10, j = 20;

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.

Example: Calling Function as Condition

static void Main(string[] args)


{
int i = 10, j = 20;

if (isGreater(i, j))
{
Console.WriteLine("i is less than j");
}

if (isGreater(j, i))
{
Console.WriteLine("j is greater than i");
}
}

static bool isGreater(int i, int j)


{
return i > j;
}
Try it

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.

Example: else if Statements

int i = 10, j = 20;

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

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.

Example: else Statement

int i = 20, j = 20;

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
}
}
}

The following example demonstrates the nested if else statements.

Example: Nested if else statements

int i = 10, j = 20;

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

Use Ternary operator ?: instead of a simple if else statement.


C# - Ternary Operator ?:

Updated on: June 24, 2020

C# includes a decision-making operator ?: which is called the


conditional operator or ternary operator. It is the short form of the  if
else conditions.

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.

The following example demonstrates the ternary operator.

Example: Ternary operator

int x = 20, y = 10;

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.

The following executes the second statement.

Example: Ternary operator


int x = 10, y = 100;

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.

Example: Ternary operator replaces if statement

int x = 10, y = 100;

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 Operator


Nested ternary operators are possible by including a conditional
expression as a second statement.

Example: Nested ?:

int x = 10, y = 100;

string result = x > y ? "x is greater than y" :


x < y ? "x is less than y" :
x == y ? "x is equal to y" : "No result";
Console.WriteLine(result);
Try it

The ternary operator is right-associative. The expression a ? b : c ?


d : e is evaluated as a ? b : (c ? d : e), not as (a ? b : c) ? d :
e.

Example: Nested ?:

var x = 2, y = 10;

var result = x * 3 > y ? x : y > z? y : z;


Console.WriteLine(result);

C# - Switch Statement

Updated on: June 25, 2020

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.

The following is the general syntax of the switch statement.

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.

The following example demonstrates a simple switch statement.

Example: C# Switch Statement


int x = 10;

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.

Example: C# Switch Statement

int x = 125;

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:

125 is an odd value

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.
Consider the following example of a simple switch statement.

Example: switch statement

string statementType = "switch";

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

Multiple cases can be combined to execute the same statements.

Example: C# Combined Switch Cases

int x = 5;

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.

The following use the return keyword.

Example: return in Switch Case

static void Main(string[] args)


{
int x = 125;
Console.Write( isOdd(x)? "Even value" : "Odd value");
}

static bool isOdd(int i, int j)


{
switch (x % 2)
{
case 0:
return true;
case 1:
return false;
default:
return false;
}

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.

Example: C# Switch Statement


int x = 1;

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;
}

Nested Switch Statements


A switch statement can be used inside another switch statement.

Example: Nested switch statements

int j = 5;

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 :

1. The switch statement is an alternative to if else statement.


2. The switch statement tests a match expression/variable against a set of
constants specified as cases.
3. The switch case must include break, return, goto keyword to exit a case.
4. The switch can include one optional default label, which will be executed
when no case executed.
5. C# compiler will give errors on missing :, constant value with cases, exit
from a case.
6. C# 7.0 onward, switch cases can include non-unique values. In this case,
the first matching case will be executed.

C# for Loop

Updated on: June 17, 2020


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.

The following for loop executes a code block 10 times.

Example: for Loop

for(int i = 0; i < 10; i++)


{
Console.WriteLine("Value of i: {0}", i);
}
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

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.


for Loop Execution
Steps

If a code block only contains a single statement, then you don't need
to wrap it inside curly brackets { }, as shown below.

Example: for Loop

for(int i = 0; i < 10; i++)


Console.WriteLine("Value of i: {0}", i);

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.

Example: for loop C#

int i = 0;

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.

Example: Infinite for Loop

for ( ; ; )
{
Console.Write(1);
}
Output:
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.

Example: Decimal for Loop

for (double d = 1.01D; d < 1.10; d+= 0.01D)


{
Console.WriteLine("Value of i: {0}", d);
}
Try it

Output:

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.

Example: Reverse for Loop

for(int i = 10; i > 0; i--)


{
Console.WriteLine("Value of i: {0}", i);
}
Try it

Output:

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

ADVERTISEMENT
Exit the for Loop
You can also exit from a for loop by using the break keyword.

Example: break in for loop

for (int i = 0; i < 10; i++)


{
if( i == 5 )
break;

Console.WriteLine("Value of i: {0}", i);


}
Try it

Output:

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.

Example: Multiple Expressions

for (int i = 0, j = 0; i+j < 5; i++, j++)


{
Console.WriteLine("Value of i: {0}, J: {1} ", i,j);
}
Try it

Output:

Value of i: 0, J: 0

Value of i: 1, J: 1

Value of i: 2, J: 2

A for loop can also contain statements as an initializer and iterator.

Example: Initializer and Iterator Statements

int i = 0, j = 5;
for (Console.WriteLine($"Initializer: i={i}, j={j}");
i++ < j--;
Console.WriteLine($"Iterator: i={i}, j={j}"))
{
}
Try it

Output:

Initializer: i=0, j=5

Iterator: i=1, j=4

Iterator: i=2, j=3

Iterator: i=3, j=2


Nested for Loop
C# allows a for loop inside another for loop.

Example: Nested for loop

for (int i = 0; i < 2; i++)


{
for(int j =i; j < 4; j++)
Console.WriteLine("Value of i: {0}, J: {1} ", i,j);
}
Try it

Output:

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.

Example: C# while Loop

int i = 0; // initialization

while (i < 10) // condition


{
Console.WriteLine("i = {0}", i);

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.

Example: Exit from the while Loop

int i = 0;

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.
Example: Infinite While Loop

int i = 0;

while (i > 0)
{
Console.WriteLine("i = {0}", i);
i++;
}

Nested while Loop


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.

Example: do-while Loop

int i = 0;

do
{
Console.WriteLine("i = {0}", i);
i++;

} while (i < 5);


Try it

Output:

i = 0

i = 1

i = 2
i = 3

i = 4

Specify initialization out of the loop and increment/decrement


counter inside do while loop.

Use break or return to exit from the do while loop.

Example: Exit from the do-while Loop

int i = 0;

do
{
Console.WriteLine("i = {0}", i);
i++;

if (i > 5)
break;

} while (i < 10);


Try it

Output:

i = 0

i = 1

i = 2

i = 3
i = 4

i = 5

Nested do-while
The do-while loop can be used inside another do-while loop.

Example: Nested do-while Loop

int i = 0;

do
{
Console.WriteLine("Value of i: {0}", i);
int j = i;

i++;

do
{
Console.WriteLine("Value of j: {0}", j);
j++;
} while (j < 2);

} while (i < 2);


Try it

Output:

i = 0

j = 0

j = 1
i = 1

j = 1

C# - Partial Classes and Methods


In C#, you can split the implementation of a class, a struct, a
method, or an interface in multiple .cs files using
the partial keyword. The compiler will combine all the
implementation from multiple .cs files when the program is
compiled.

Consider the following EmployeeProps.cs and EmployeeMethods.cs files


that contain the Employee class.

EmployeeProps.cs

public partial class Employee


{
public int EmpId { get; set; }
public string Name { get; set; }
}
EmployeeMethods.cs

public partial class Employee


{
//constructor
public Employee(int id, string name){
this.EmpId = id;
this.Name = name;
}

public void DisplayEmpInfo() {


Console.WriteLine(this.EmpId + " " this.Name);
}
}
Above, EmployeeProps.cs contains properties of the Employee class,
and EmployeeMethods.cs contains all the methods of
the Employee class. These will be compiled as one Employee class.

Example: Combined Class

public class Employee


{
public int EmpId { get; set; }
public string Name { get; set; }

public Employee(int id, string name){


this.EmpId = id;
this.Name = name;
}

public void DisplayEmpInfo(){


Console.WriteLine(this.EmpId + " " this.Name );
}
}

Rules for Partial Classes


 All the partial class definitions must be in the same assembly and
namespace.
 All the parts must have the same accessibility like public or private, etc.
 If any part is declared abstract, sealed or base type then the whole class is
declared of the same type.
 Different parts can have different base types and so the final class will inherit
all the base types.
 The Partial modifier can only appear immediately before the
keywords class, struct, or interface.
 Nested partial types are allowed.

Partial Methods
Partial classes or structs can contain a method that split into two
separate .cs files of the partial class or struct. One of the
two .cs files must contain a signature of the method, and other file
can contain an optional implementation of the partial method. Both
declaration and implementation of a method must have
the partial keyword.
EmployeeProps.cs

public partial class Employee


{
public Employee() {
GenerateEmpId();
}
public int EmpId { get; set; }
public string Name { get; set; }

partial void GenerateEmployeeId();

}
EmployeeMethods.cs

public partial class Employee


{
partial void GenerateEmployeeId()
{
this.EmpId = random();
}
}

Above, EmployeeProps.cs contains the declaration of the partial


method GenerateEmployeeId() which is being used in the
constructor. EmployeeMethods.cs contains the implementation of
the GenerateEmployeeId() method. The following demonstrates
creates an object the Employee class which used the partial method.

EmployeeMethods.cs
class Program
{
static void Main(string[] args)
{
var emp = new Employee();
Console.WriteLine(emp.EmpId); // prints genereted id

Console.ReadLine();
}
}
Rules for Partial Methods
 Partial methods must use the partial keyword and must return void.
 Partial methods can have in or ref but not out parameters.
 Partial methods are implicitly private methods, so cannot be virtual.
 Partial methods can be static methods.
 Partial methods can be generic.

C# - Static Class, Methods, Constructors,


Fields

Updated on: June 28, 2020

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.

Example: C# Static Class

public static class Calculator


{
private static int _resultStorage = 0;

public static string Type = "Arithmetic";


public static int Sum(int num1, int num2)
{
return num1 + num2;
}

public static void Store(int result)


{
_resultStorage = result;
}
}

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.

Example: Accessing Static Members

class Program
{
static void Main(string[] args)
{
var result = Calculator.Sum(10, 25); // calling static method
Calculator.Store(result);

var calcType = Calculator.Type; // accessing static variable


Calculator.Type = "Scientific"; // assign value to static
variable
}
}
Try it

Rules for Static Class


1. Static classes cannot be instantiated.
2. All the members of a static class must be static; otherwise the compiler will
give an error.
3. A static class can contain static variables, static methods, static properties,
static operators, static events, and static constructors.
4. A static class cannot contain instance members and constructors.
5. Indexers and destructors cannot be static
6. var cannot be used to define static members. You must specify a type of
member explicitly after the static keyword.
7. Static classes are sealed class and therefore, cannot be inherited.
8. A static class cannot inherit from other classes.
9. Static class members can be accessed using ClassName.MemberName.
10. A static class remains in memory for the lifetime of the application
domain in which your program resides.

Static Members in Non-static Class


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.

Example: Shared Static Fields

public class StopWatch


{
public static int InstanceCounter = 0;
// instance constructor
public StopWatch()
{
}
}

class Program
{
static void Main(string[] args)
{
StopWatch sw1 = new StopWatch();
StopWatch sw2 = new StopWatch();
Console.WriteLine(StopWatch.NoOfInstances); //2
StopWatch sw3 = new StopWatch();
StopWatch sw4 = new StopWatch();
Console.WriteLine(StopWatch.NoOfInstances);//4
}
}
Try it
ADVERTISEMENT

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.

Example: Static Method

class Program
{
static int counter = 0;
string name = "Demo Program";

static void Main(string[] args)


{
counter++; // can access static fields
Display("Hello World!"); // can call static methods

name = "New Demo Program"; //Error: cannot access non-static


members
SetRootFolder("C:\MyProgram"); //Error: cannot call non-static
method
}

static void Display(string text)


{
Console.WriteLine(text);
}

public void SetRootFolder(string path) { }


}
Rules for 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.

Example: Static Constructor vs Instance Constructor

public class StopWatch


{
// static constructor
static StopWatch()
{
Console.WriteLine("Static constructor called");
}

// 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.

Example: Static Constructor Execution

StopWatch.DisplayInfo(); // static constructor called here


StopWatch.DisplayInfo(); // none of the constructors called here
Output:

Static constructor called.

DisplayInfo called

DisplayInfo called

The following example shows that the static constructor gets called
when you create an instance for the first time.

Example: Static Constructor Execution

StopWatch sw1 = new StopWatch(); // First static constructor and then


instance constructor called
StopWatch sw2 = new StopWatch();// only instance constructor called
StopWatch.DisplayInfo();
Output:
Static constructor called

instance constructor called

instance constructor called

DisplayInfo called

Rules for Static Constructors


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.

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.

The following figure illustrates an array representation.

Array Representation

Array Declaration and Initialization


An array can be declared using by specifying the type of its elements
with square brackets.

Example: Array Declaration

int[] evenNums; // integer array

string[] cities; // string array

The following declares and adds values into an array in a single


statement.

Example: Array Declaration & Initialization

int[] evenNums = new int[5]{ 2, 4, 6, 8, 10 };

string[] cities = new string[3]{ "Mumbai", "London", "New York" };

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.
Example: Array Declaration using var

var evenNums = new int[]{ 2, 4, 6, 8, 10};

var cities = new string[]{ "Mumbai", "London", "New York" };

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.

Example: Short Syntax of Array Declaration

int[] evenNums = { 2, 4, 6, 8, 10};

string[] cities = { "Mumbai", "London", "New York" }

The following example demonstrate invalid array declarations.

Example: Invalid Array Creation

//must specify the size


int[] evenNums = new int[];

//number of elements must be equal to the specified size


int[] evenNums = new int[5] { 2, 4 };

//cannot use var with array initializer


var evenNums = { 2, 4, 6, 8, 10};

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.

Example: Late Initialization

int[] evenNums;

evenNums = new int[5];


// or
evenNums = new int[]{ 2, 4, 6, 8, 10 };
ADVERTISEMENT
Accessing Array Elements
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.

Example: Access Array Elements using Indexes

int[] evenNums = new int[5];


evenNums[0] = 2;
evenNums[1] = 4;
//evenNums[6] = 12; //Throws run-time exception IndexOutOfRange

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.

Accessing Array using for Loop


Use the for loop to access array elements. Use the length property
of an array in conditional expression of the for loop.

Example: Accessing Array Elements using for Loop

int[] evenNums = { 2, 4, 6, 8, 10 };

for(int i = 0; i < evenNums.Length; i++)


Console.WriteLine(evenNums[i]);

for(int i = 0; i < evenNums.Length; i++)


evenNums[i] = evenNums[i] + 10; // update the value of each
element by 10
Try it
Accessing Array using foreach Loop
Use foreach loop to read values of an array elements without using
index.

Example: Accessing Array using foreach Loop

int[] evenNums = { 2, 4, 6, 8, 10};


string[] cities = { "Mumbai", "London", "New York" };

foreach(var item in evenNums)


Console.WriteLine(item);

foreach(var city in cities)


Console.WriteLine(city);
Try it

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.

Example: LINQ Methods

int[] nums = new int[5]{ 10, 15, 16, 8, 6 };

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.

Example: Array Methods


int[] nums = new int[5]{ 10, 15, 16, 8, 6 };

Array.Sort(nums); // sorts array


Array.Reverse(nums); // sorts array in descending order
Array.ForEach(nums, n => Console.WriteLine(n)); // iterates array
Array.BinarySearch(nums, 5);// binary search
Try it

Passing Array as Argument


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);

foreach(var item in nums)


Console.WriteLine(item);
}

public static void UpdateArray(int[] arr)


{
for(int i = 0; i < arr.Length; i++)
arr[i] = arr[i] + 10;
}

C# - Multidimensional Arrays
C# supports multidimensional arrays up to 32 dimensions. The
multidimensional array can be declared by adding commas in the
square brackets. For example, [,] declares two-dimensional array,
[, ,] declares three-dimensional array, [, , ,] declares four-
dimensional array, and so on. So, in a multidimensional array, no of
commas = No of Dimensions - 1.

The following declares multidimensional arrays.


Example: Multidimensional Arrays

int[,] arr2d; // two-dimensional array


int[, ,] arr3d; // three-dimensional array
int[, , ,] arr4d ; // four-dimensional array
int[, , , ,] arr5d; // five-dimensional array

Let's understand the two-dimensional array. The following initializes


the two-dimensional array.

Example: two-dimensional Array

int[,] arr2d = new int[3,2]{


{1, 2},
{3, 4},
{5, 6}
};

// 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

The following access values of the two-dimensional array.


Example: Access two-dimensional Array

int[,] arr2d = new int[3,2]{


{1, 2},
{3, 4},
{5, 6}
};

arr2d[0, 0]; //returns 1


arr2d[0, 1]; //returns 2
arr2d[1, 0]; //returns 3
arr2d[1, 1]; //returns 4
arr2d[2, 0]; //returns 5
arr2d[2, 1]; //returns 6
//arr2d[3, 0]; //throws run-time error as there is no 4th row
Try it

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.

Example: Three-dimensional Array

int[, ,] arr3d1 = new int[1, 2, 2]{


{ { 1, 2}, { 3, 4} }
};

int[, ,] arr3d2 = new int[2, 2, 2]{


{ {1, 2}, {3, 4} },
{ {5, 6}, {7, 8} }
};

int[, ,] arr3d3 = new int[2, 2, 3]{


{ { 1, 2, 3}, {4, 5, 6} },
{ { 7, 8, 9}, {10, 11, 12} }
};

arr3d2[0, 0, 0]; // returns 1


arr3d2[0, 0, 1]; // returns 2
arr3d2[0, 1, 0]; // returns 3
arr3d2[0, 1, 1]; // returns 4
arr3d2[1, 0, 0]; // returns 5
arr3d2[1, 0, 1]; // returns 6
arr3d2[1, 1, 0]; // returns 7
arr3d2[1, 1, 1]; // returns 8
Try it

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.

Now, consider the following four-dimensional array.

Example: Four-dimensional Array

int[,,,] arr4d1 = new int[1, 1, 2, 2]{


{
{ { 1, 2}, { 3, 4} }
}
};

arr4d1[0, 0, 0, 0]; // returns 1


arr4d1[0, 0, 0, 1]; // returns 2
arr4d1[0, 0, 1, 0]; // returns 3
arr4d1[0, 0, 1, 1]; // returns 4

int[,,,] arr4d2 = new int[1, 2, 2, 2]{


{
{ {1, 2}, {3, 4} },
{ {5, 6}, {7, 8} }
}
};

arr4d2[0, 0, 0, 0]; // returns 1


arr4d2[0, 0, 0, 1]; // returns 2
arr4d2[0, 0, 1, 0]; // returns 3
arr4d2[0, 0, 1, 1]; // returns 4
arr4d2[0, 1, 0, 0]; // returns 5
arr4d2[0, 1, 0, 1]; // returns 6
arr4d2[0, 1, 1, 0]; // returns 7
arr4d2[0, 1, 1, 1]; // returns 8
Try it
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#.

C# Jagged Arrays: An Array of Array


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.

The following example declares jagged arrays.

Example: Jagged Arrays

int[][] jArray1 = new int[2][]; // can include two single-dimensional


arrays
int[][,] jArray2 = new int[3][,]; // can include three two-dimensional
arrays

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.

Example: Jagged Array

int[][] jArray = new int[2][];

jArray[0] = new int[3]{1, 2, 3};

jArray[1] = new int[4]{4, 5, 6, 7 };

You can also initialize a jagged array upon declaration like the below.

Example: Jagged Array


int[][] jArray = new int[2][]{
new int[3]{1, 2, 3},

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.

Example: Jagged Array

int[][] jArray = new int[2][]{


new int[3]{1, 2, 3},

new int[4]{4, 5, 6, 7}
};

for(int i=0; i<jArray.Length; i++)


{
for(int j=0; j < (jArray[i]).Length; j++)
Console.WriteLine(jArray[i][j]);
}
Try it

The following jagged array stores two-dimensional arrays where the


second bracket [,] indicates the two-dimensional array.

Example: Jagged Array

int[][,] jArray = new int[2][,];

jArray[0] = new int[3, 2] { { 1, 2 }, { 3, 4 }, { 5, 6 } };


jArray[1] = new int[2, 2] { { 7, 8 }, { 9, 10 } };

jArray[0][1, 1]; //returns 4

jArray[1][1, 0]; //returns 9


jArray[1][1, 1]; //returns 10
Try it

If you add one more bracket then it will be array of array of arry.

Example: Jagged Array

int[][][] intJaggedArray = new int[2][][]


{
new int[2][]
{
new int[3] { 1, 2, 3},
new int[2] { 4, 5}
},
new int[1][]
{
new int[3] { 7, 8, 9}
}
};

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# Indexers
An indexer is a special type of property that allows a class or a
structure to be accessed like an array for its internal collection. C#
allows us to define custom indexers, generic indexers, and also
overload indexers.

An indexer can be defined the same way as property


with this keyword and square brackets [].

Syntax

<return type> this[<parameter type> index]


{
get{
// return the value from the specified index of an internal collection
}
set{
// set values at the specified index in an internal collection
}
}

The following example defines an indexer in the class.

Example: Indexer

class StringDataStore
{
private string[] strArr = new string[10]; // internal data storage

public string this[int index]


{
get
{
if (index < 0 || index >= strArr.Length)
throw new IndexOutOfRangeException("Index out of
range");

return strArr[index];
}

set
{
if (index < 0 || index >= strArr.Length)
throw new IndexOutOfRangeException("Index out of
range");

strArr[index] = value;
}
}
}

The above StringDataStore class defines an indexer for its private


array strArr. So now, you can use the StringDataStore like an array
to add and retrieve string values from strArr, as shown below.

Example: Indexer

StringDataStore strStore = new StringDataStore();

strStore[0] = "One";
strStore[1] = "Two";
strStore[2] = "Three";
strStore[3] = "Four";

for(int i = 0; i < 10 ; i++)


Console.WriteLine(strStore[i]);
Try it

Output:
One

Two

Three

Four

You can use expression-bodied syntax for get and set from C# 7
onwards.

Example: Indexer

class StringDataStore
{
private string[] strArr = new string[10]; // internal data storage

public string this[int index]


{
get => strArr[index];

set => strArr[index] = value;


}
}
Try it
ADVERTISEMENT

Generic Indexer
Indexer can also be generic. The following generic class includes
generic indexer.

Example: Generic Indexer

class DataStore<T>
{
private T[] store;
public DataStore()
{
store = new T[10];
}

public DataStore(int length)


{
store = new T[length];
}

public T this[int index]


{
get
{
if (index < 0 && index >= store.Length)
throw new IndexOutOfRangeException("Index out of
range");

return store[index];
}

set
{
if (index < 0 || index >= store.Length)
throw new IndexOutOfRangeException("Index out of
range");

store[index] = value;
}
}

public int Length


{
get
{
return store.Length;
}
}
}
Try it

The above generic indexer can be used with any data type. The
following example demonstrates the use of generic indexer.

Example:
DataStore<int> grades = new DataStore<int>();
grades[0] = 100;
grades[1] = 25;
grades[2] = 34;
grades[3] = 42;
grades[4] = 12;
grades[5] = 18;
grades[6] = 2;
grades[7] = 95;
grades[8] = 75;
grades[9] = 53;

for (int i = 0; i < grades.Length;i++)


Console.WriteLine(grades[i]);

DataStore<string> names = new DataStore<string>(5);


names[0] = "Steve";
names[1] = "Bill";
names[2] = "James";
names[3] = "Ram";
names[4] = "Andy";

for (int i = 0; i < names.Length;i++)


Console.WriteLine(names[i]);
Try it

Overload Indexer
You can be overloaded with the different data types for index. The
following example overloads an indexer with int type index as well as
string type index.

Example: Override Indexer

class StringDataStore
{
private string[] strArr = new string[10]; // internal data storage

// int type indexer


public string this[int index]
{
get
{
if (index < 0 || index >= strArr.Length)
throw new IndexOutOfRangeException("Index out of
range");

return strArr[index];
}

set
{
if (index < 0 || index >= strArr.Length)
throw new IndexOutOfRangeException("Index out of
range");

strArr[index] = value;
}
}

// string type indexer


public string this[string name]
{
get
{
foreach (string str in strArr){
if(str.ToLower() == name.ToLower())
return str;
}

return null;
}
}
}

class Program
{
static void Main(string[] args)
{
StringDataStore strStore = new StringDataStore();

strStore[0] = "One";
strStore[1] = "Two";
strStore[2] = "Three";
strStore[3] = "Four";

Console.WriteLine(strStore["one"]);
Console.WriteLine(strStore["two"]);
Console.WriteLine(strStore["Three"]);
Console.WriteLine(strStore["Four"]);
}
}
Try it

 Note:

Indexer does not allow ref and out paramters.

C# Generics
Generic means the general form, not specific. In C#, generic means
not specific to a particular data type.

C# allows you to define generic classes, interfaces, abstract classes,


fields, methods, static methods, properties, events, delegates, and
operators using the type parameter and without the specific data
type. A type parameter is a placeholder for a particular type specified
when creating an instance of the generic type.

A generic type is declared by specifying a type parameter in an angle


brackets after a type name, e.g. TypeName<T> where T is a type
parameter.

Generic Class
Generic classes are defined using a type parameter in an angle
brackets after the class name. The following defines a generic class.

Example: Define Generic Class

class DataStore<T>
{
public T Data { get; set; }
}

Above, the DataStore is a generic class. T is called type parameter,


which can be used as a type of fields, properties, method
parameters, return types, and delegates in the DataStore class. For
example, Data is generic property because we have used a type
parameter T as its type instead of the specific data type.
 Note

It is not required to use T as a type parameter. You can give any name to a type
parameter. Generally, T is used when there is only one type parameter. It is
recommended to use a more readable type parameter name as per requirement
like TSession, TKey, TValue etc. Learn more about Type Parameter Naming
Guidelines

You can also define multiple type parameters separated by a comma.

Example: Generic Class with Multiple Type Parameters

class KeyValuePair<TKey, TValue>


{
public TKey Key { get; set; }
public TValue Value { get; set; }
}

Instantiating Generic Class


You can create an instance of generic classes by specifying an actual
type in angle brackets. The following creates an instance of the
generic class DataStore.

DataStore<string> store = new DataStore<string>();

Above, we specified the string type in the angle brackets while


creating an instance. So, T will be replaced with a string type
wherever T is used in the entire class at compile-time. Therefore, the
type of Data property would be a string.

The following figure illustrates how generics works.


You can assign a string value to the Data property. Trying to assign
values other than string will result in a compile-time error.

DataStore<string> store = new DataStore<string>();


store.Data = "Hello World!";
//obj.Data = 123; //compile-time error

You can specify the different data types for different objects, as
shown below.

Example: Generic class

DataStore<string> strStore = new DataStore<string>();


strStore.Data = "Hello World!";
//strStore.Data = 123; // compile-time error

DataStore<int> intStore = new DataStore<int>();


intStore.Data = 100;
//intStore.Data = "Hello World!"; // compile-time error

KeyValuePair<int, string> kvp1 = new KeyValuePair<int, string>();


kvp1.Key = 100;
kvp1.Value = "Hundred";

KeyValuePair<string, string> kvp2 = new KeyValuePair<string,


string>();
kvp2.Key = "IT";
kvp2.Value = "Information Technology";
Try it
ADVERTISEMENT

Generic Class Characteristics


 A generic class increases the reusability. The more type parameters mean
more reusable it becomes. However, too much generalization makes code
difficult to understand and maintain.
 A generic class can be a base class to other generic or non-generic classes or
abstract classes.
 A generic class can be derived from other generic or non-generic interfaces,
classes, or abstract classes.
Generic Fields
A generic class can include generic fields. However, it cannot be
initialized.

Example: Generic Field

class DataStore<T>
{
public T data;
}

The following declares a generic array.

Example: Generic Array

class DataStore<T>
{
public T[] data = new T[10];
}

Generic Methods
A method declared with the type parameters for its return type or
parameters is called a generic method.

Example: Generic Methods

class DataStore<T>
{
private T[] _data = new T[10];

public void AddOrUpdate(int index, T item)


{
if(index >= 0 && index < 10)
_data[index] = item;
}

public T GetData(int index)


{
if(index >= 0 && index < 10)
return _data[index];
else
return default(T);
}
}

Above, the AddorUpdate() and the GetData() methods are generic


methods. The actual data type of the item parameter will be specified
at the time of instantiating the DataStore<T> class, as shown below.

Example: Generic Methods

DataStore<string> cities = new DataStore<string>();


cities.AddOrUpdate(0, "Mumbai");
cities.AddOrUpdate(1, "Chicago");
cities.AddOrUpdate(2, "London");

DataStore<int> empIds = new DataStore<int>();


empIds.AddOrUpdate(0, 50);
empIds.AddOrUpdate(1, 65);
empIds.AddOrUpdate(2, 89);
Try it

The generic parameter type can be used with multiple parameters


with or without non-generic parameters and return type. The
followings are valid generic method overloading.

Example: Generic Method Overloading

public void AddOrUpdate(int index, T data) { }


public void AddOrUpdate(T data1, T data2) { }
public void AddOrUpdate<U>(T data1, U data2) { }
public void AddOrUpdate(T data) { }

A non-generic class can include generic methods by specifying a type


parameter in angle brackets with the method name, as shown below.

Example: Generic Method in Non-generic Class

class Printer
{
public void Print<T>(T data)
{
Console.WriteLine(data);
}
}
Printer printer = new Printer();
printer.Print<int>(100);
printer.Print(200); // type infer from the specified value
printer.Print<string>("Hello");
printer.Print("World!"); // type infer from the specified value
Try it

Advantages of Generics
1. Generics increase the reusability of the code. You don't need to write code to
handle different data types.
2. Generics are type-safe. You get compile-time errors if you try to use a
different data type than the one specified in the definition.
3. Generic has a performance advantage because it removes the possibilities of
boxing and unboxing.

C# Generic Constraints
C# allows you to use constraints to restrict client code to specify
certain types while instantiating generic types. It will give a compile-
time error if you try to instantiate a generic type using a type that is
not allowed by the specified constraints.

You can specify one or more constraints on the generic type using
the where clause after the generic type name.

Syntax:

GenericTypeName<T> where T : contraint1, constraint2

The following example demonstrates a generic class with a constraint


to reference types when instantiating the generic class.

Example: Declare Generic Constraints

class DataStore<T> where T : class


{
public T Data { get; set; }
}
Above, we applied the class constraint, which means only a reference
type can be passed as an argument while creating the DataStore
class object. So, you can pass reference types such as class,
interface, delegate, or array type. Passing value types will give a
compile-time error, so we cannot pass primitive data types or struct
types.

DataStore<string> store = new DataStore<string>(); // valid


DataStore<MyClass> store = new DataStore<MyClass>(); // valid
DataStore<IMyInterface> store = new DataStore<IMyInterface>(); //
valid
DataStore<IEnumerable> store = new DataStore<IMyInterface>(); // valid
DataStore<ArrayList> store = new DataStore<ArrayList>(); // valid
//DataStore<int> store = new DataStore<int>(); // compile-time error

The following table lists the types of generic constraints.

Constraint Description

class The type argument must be any class, interface, delegate, or array type.

class? The type argument must be a nullable or non-nullable class, interface, delegate, or array type.

struct The type argument must be non-nullable value types such as primitive data types int, char, bool, float, etc.

new() The type argument must be a reference type which has a public parameterless constructor. It cannot be
combined with struct and unmanaged constraints.

notnull Available C# 8.0 onwards. The type argument can be non-nullable reference types or value types. If not, then
the compiler generates a warning instead of an error.

unmanaged The type argument must be non-nullable unmanged types.

base class The type argument must be or derive from the specified base class. The Object, Array, ValueType classes are
name disallowed as a base class constraint. The Enum, Delegate, MulticastDelegate are disallowed as base class
constraint before C# 7.3.

<base class The type argument must be or derive from the specified nullable or non-nullable base class
name>?

<interface The type argument must be or implement the specified interface.


name>

<interface The type argument must be or implement the specified interface. It may be a nullable reference type, a non-
name>? nullable reference type, or a value type

where T: U The type argument supplied for T must be or derive from the argument supplied for U.
Constraint Description

where T : struct
The following example demonstrates the struct constraint that
restricts type argument to be non-nullable value type only.

Example: struct Constraints

class DataStore<T> where T : struct


{
public T Data { get; set; }
}

DataStore<int> store = new DataStore<int>(); // valid


DataStore<char> store = new DataStore<char>(); // valid
DataStore<MyStruct> store = new DataStore<MyStruct>(); // valid
//DataStore<string> store = new DataStore<string>(); // compile-time
error
//DataStore<IMyInterface> store = new DataStore<IMyInterface>(); //
compile-time error
//DataStore<ArrayList> store = new DataStore<ArrayList>(); // compile-
time error

where T : new()
The following example demonstrates the struct constraint that
restricts type argument to be non-nullable value type only.

Example: new() Constraint

class DataStore<T> where T : class, new()


{
public T Data { get; set; }
}

DataStore<MyClass> store = new DataStore<MyClass>(); // valid


DataStore<ArrayList> store = new DataStore<ArrayList>(); // valid
//DataStore<string> store = new DataStore<string>(); // compile-time
error
//DataStore<int> store = new DataStore<int>(); // compile-time error
//DataStore<IMyInterface> store = new DataStore<IMyInterface>(); //
compile-time error

where T : baseclass
The following example demonstrates the base class constraint that
restricts type argument to be a derived class of the specified class,
abstract class, or an interface.

Example: BaseClass Constraint

class DataStore<T> where T : IEnumerable


{
public T Data { get; set; }
}

DataStore<ArrayList> store = new DataStore<ArrayList>(); // valid


DataStore<List> store = new DataStore<List>(); // valid
//DataStore<string> store = new DataStore<string>(); // compile-time
error
//DataStore<int> store = new DataStore<int>(); // compile-time error
//DataStore<IMyInterface> store = new DataStore<IMyInterface>(); //
compile-time error
//DataStore<MyClass> store = new DataStore<MyClass>(); // compile-time
error

C# Generic & Non-generic Collections


C# includes specialized classes that store series of values or objects
are called collections.

There are two types of collections available in C#: non-generic


collections and generic collections.

The System.Collections namespace contains the non-generic


collection types and System.Collections.Generic namespace includes
generic collection types.
In most cases, it is recommended to use the generic collections
because they perform faster than non-generic collections and also
minimize exceptions by giving compile-time errors.

Generic Collections
C# includes the following generic collection classes in
the System.Collections.Generic namespace.

Generic Collections Description

List<T> Generic List<T> contains elements of specified type. It grows automatically as you add elements in
it.

Dictionary<TKey,TValue> Dictionary<TKey,TValue> contains key-value pairs.

SortedList<TKey,TValue> SortedList stores key and value pairs. It automatically adds the elements in ascending order of key
by default.

Queue<T> Queue<T> stores the values in FIFO style (First In First Out). It keeps the order in which the values
were added. It provides an Enqueue() method to add values and a Dequeue() method to retrieve
values from the collection.

Stack<T> Stack<T> stores the values as LIFO (Last In First Out). It provides a Push() method to add a value and
Pop() & Peek() methods to retrieve values.

Hashset<T> Hashset<T> contains non-duplicate elements. It eliminates duplicate elements.

Non-generic Collections
Non-generic
Collections Usage

ArrayList ArrayList stores objects of any type like an array. However, there is no need to specify the size of the
ArrayList like with an array as it grows automatically.

SortedList SortedList stores key and value pairs. It automatically arranges elements in ascending order of key by
default. C# includes both, generic and non-generic SortedList collection.

Stack Stack stores the values in LIFO style (Last In First Out). It provides a Push() method to add a value and Pop()
& Peek() methods to retrieve values. C# includes both, generic and non-generic Stack.

Queue Queue stores the values in FIFO style (First In First Out). It keeps the order in which the values were added. It
provides an Enqueue() method to add values and a Dequeue() method to retrieve values from the collection.
Non-generic
Collections Usage

C# includes generic and non-generic Queue.

Hashtable Hashtable stores key and value pairs. It retrieves the values by comparing the hash value of the keys.

BitArray BitArray manages a compact array of bit values, which are represented as Booleans, where true indicates
that the bit is on (1) and false indicates the bit is off (0).

C# - ArrayList
In C#, the ArrayList is a non-generic collection of objects whose size
increases dynamically. It is the same as Array except that its size
increases dynamically.

An ArrayList can be used to add unknown data where you don't


know the types and the size of the data.

Create an ArrayList
The ArrayList class included in the System.Collections namespace.
Create an object of the ArrayList using the new keyword.

Example: Create an ArrayList

using System.Collections;

ArrayList arlist = new ArrayList();


// or
var arlist = new ArrayList(); // recommended

Adding Elements in ArrayList


Use the Add() method or object initializer syntax  to add elements in
an ArrayList.

An ArrayList can contain multiple null and duplicate values.


Example: Adding Elements in ArrayList

// adding elements using ArrayList.Add() method


var arlist1 = new ArrayList();
arlist1.Add(1);
arlist1.Add("Bill");
arlist1.Add(" ");
arlist1.Add(true);
arlist1.Add(4.5);
arlist1.Add(null);

// adding elements using object initializer syntax


var arlist2 = new ArrayList()
{
2, "Steve", " ", true, 4.5, null
};
Try it

Use the AddRange(ICollection c) method to add an


entire Array, HashTable, SortedList, ArrayList, BitArray, Queue,
and Stack in the ArrayList.

Example: Adding Entire Array/ArrayList into ArrayList

var arlist1 = new ArrayList();

var arlist2 = new ArrayList()


{
1, "Bill", " ", true, 4.5, null
};

int[] arr = { 100, 200, 300, 400 };

Queue myQ = new Queue();


myQ.Enqueue("Hello");
myQ.Enqueue("World!");

arlist1.AddRange(arlist2); //adding arraylist in arraylist


arlist1.AddRange(arr); //adding array in arraylist
arlist1.AddRange(myQ); //adding Queue in arraylist
Try it
Accessing an ArrayList
The ArrayList class implements the IList interface. So, elements
can be accessed using indexer, in the same way as an array. Index
starts from zero and increases by one for each subsequent element.

An explicit casting to the appropriate types is required, or use


the var variable.

Example: Accessing Elements of ArrayList

var arlist = new ArrayList()


{
1,
"Bill",
300,
4.5f
};

//Access individual item using indexer


int firstElement = (int) arlist[0]; //returns 1
string secondElement = (string) arlist[1]; //returns "Bill"
//int secondElement = (int) arlist[1]; //Error: cannot cover string to
int

//using var keyword without explicit casting


var firstElement = arlist[0]; //returns 1
var secondElement = arlist[1]; //returns "Bill"
//var fifthElement = arlist[5]; //Error: Index out of range

//update elements
arlist[0] = "Steve";
arlist[1] = 100;
//arlist[5] = 500; //Error: Index out of range
Try it
ADVERTISEMENT

Iterate an ArrayList
The ArrayList implements the ICollection interface that supports
iteration of the collection types. So, use the foreach and the for loop
to iterate an ArrayList. The Count property of an ArrayList returns
the total number of elements in an ArrayList.

Example: Iterate ArrayList

ArrayList arlist = new ArrayList()


{
1,
"Bill",
300,
4.5F
};

foreach (var item in arlist)


Console.Write(item + ", "); //output: 1, Bill, 300, 4.5,

for(int i = 0 ; i < arlist.Count; i++)


Console.Write(arlist[i] + ", "); //output: 1, Bill, 300, 4.5,
Try it

Insert Elements in ArrayList


Use the Insert() method to insert an element at the specified index
into an ArrayList.

Signature: void Insert(int index, Object value)

Example: Insert Element in ArrayList

ArrayList arlist = new ArrayList()


{
1,
"Bill",
300,
4.5f
};

arlist.Insert(1, "Second Item");

foreach (var val in arlist)


Console.WriteLine(val);
Try it
Use the InsertRange() method to insert a collection in
an ArrayList at the specfied index.

Signature: Void InsertRange(int index, ICollection c)

Example: Insert Collection in ArrayList

ArrayList arlist1 = new ArrayList()


{
100, 200, 600
};

ArrayList arlist2 = new ArrayList()


{
300, 400, 500
};
arlist1.InsertRange(2, arlist2);

foreach(var item in arlist1)


Console.Write(item + ", "); //output: 100, 200, 300, 400, 500,
600,
Try it

Remove Elements from ArrayList


Use the Remove(), RemoveAt(), or RemoveRange methods to remove
elements from an ArrayList.

Example: Remove Elements from ArrayList

ArrayList arList = new ArrayList()


{
1,
null,
"Bill",
300,
" ",
4.5f,
300,
};

arList.Remove(null); //Removes first occurance of null


arList.RemoveAt(4); //Removes element at index 4
arList.RemoveRange(0, 2);//Removes two elements starting from 1st item
(0 index)
Try it

Check Element in ArrayList


Use the Contains() method to determine whether the specified
element exists in the ArrayList or not. It returns true if exists
otherwise returns false.

Example: Check for Elements

ArrayList arList = new ArrayList()


{
1,
"Bill",
300,
4.5f,
300
};

Console.WriteLine(arList.Contains(300)); // true
Console.WriteLine(arList.Contains("Bill")); // true
Console.WriteLine(arList.Contains(10)); // false
Console.WriteLine(arList.Contains("Steve")); // false
Try it

 Note:

It is not recommended to use the ArrayList class due to performance issue.


Instead, use List<object> to store heterogeneous objects. To store data of same
data type, use Generic List<T>.

ArrayList Class
The following diagram illustrates the ArrayList class.
C# ArrayList
ArrayList Properties
Properties Description

Capacity Gets or sets the number of elements that the ArrayList can contain.

Count Gets the number of elements actually contained in the ArrayList.

IsFixedSize Gets a value indicating whether the ArrayList has a fixed size.

IsReadOnly Gets a value indicating whether the ArrayList is read-only.

Item Gets or sets the element at the specified index.

ArrayList Methods
Methods Description

Add()/AddRange() Add() method adds single elements at the end of ArrayList.


AddRange() method adds all the elements from the specified collection into ArrayList.

Insert()/InsertRange() Insert() method insert a single elements at the specified index in ArrayList.
InsertRange() method insert all the elements of the specified collection starting from specified
index in ArrayList.

Remove()/RemoveRange( Remove() method removes the specified element from the ArrayList.
) RemoveRange() method removes a range of elements from the ArrayList.

RemoveAt() Removes the element at the specified index from the ArrayList.

Sort() Sorts entire elements of the ArrayList.

Reverse() Reverses the order of the elements in the entire ArrayList.

Contains Checks whether specified element exists in the ArrayList or not. Returns true if exists otherwise
false.

Clear Removes all the elements in ArrayList.

CopyTo Copies all the elements or range of elements to compitible Array.

GetRange Returns specified number of elements from specified index from ArrayList.

IndexOf Search specified element and returns zero based index if found. Returns -1 if element not found.

ToArray Returns compitible array from an ArrayList.


C# - List<T>
The List<T> is a collection of strongly typed objects that can be
accessed by index and having methods for sorting, searching, and
modifying list. It is the generic version of the ArrayList that comes
under System.Collection.Generic namespace.

List<T> Characteristics
 List<T> equivalent of the ArrayList, which implements IList<T>.
 It comes under System.Collection.Generic namespace.
 List<T> can contain elements of the specified type. It provides compile-time
type checking and doesn't perform boxing-unboxing because it is generic.
 Elements can be added using the Add(), AddRange() methods or collection-
initializer syntax.
 Elements can be accessed by passing an index e.g. myList[0]. Indexes
start from zero.
 List<T> performs faster and less error-prone than the ArrayList.

Creating a List
The List<T> is a generic collection, so you need to specify a type
parameter for the type of data it can store. The following example
shows how to create list and add elements.

Example: Adding elements in List

List<int> primeNumbers = new List<int>();


primeNumbers.Add(1); // adding elements using add() method
primeNumbers.Add(3);
primeNumbers.Add(5);
primeNumbers.Add(7);

var cities = new List<string>();


cities.Add("New York");
cities.Add("London");
cities.Add("Mumbai");
cities.Add("Chicago");
cities.Add(null);// nulls are allowed for reference type list
//adding elements using collection-initializer syntax
var bigCities = new List<string>()
{
"New York",
"London",
"Mumbai",
"Chicago"
};
Try it

In the above example, List<int> primeNumbers = new


List<int>(); creates a list of int type. In the same
way, cities and bigCities are string type list. You can then add
elements in a list using the Add() method or the collection-initializer
syntax.

You can also add elements of the custom classes using the collection-
initializer syntax. The following adds objects of the Student class in
the List<Student>.

Example: Add Custom Class Objects in List

var students = new List<Student>() {


new Student(){ Id = 1, Name="Bill"},
new Student(){ Id = 2, Name="Steve"},
new Student(){ Id = 3, Name="Ram"},
new Student(){ Id = 4, Name="Abdul"}
};

Adding an Array in a List


Use the AddRange() method to add all the elements from an array or
another collection to List.

AddRange() signature: void AddRange(IEnumerable<T> collection)

Example: Add Arrays in List

string[] cities = new string[3]{ "Mumbai", "London", "New York" };

var popularCities = new List<string>();

// adding an array in a List


popularCities.AddRange(cities);

var favouriteCities = new List<string>();

// adding a List
favouriteCities.AddRange(popularCities);
Try it

Accessing a List
A list can be accessed by an index, a for/foreach loop, and using
LINQ queries. Indexes of a list start from zero. Pass an index in the
square brackets to access individual list items, same as array. Use
a foreach or for loop to iterate a List<T> collection.

Example: Accessing List

List<int> numbers = new List<int>() { 1, 2, 5, 7, 8, 10 };


Console.WriteLine(numbers[0]); // prints 1
Console.WriteLine(numbers[1]); // prints 2
Console.WriteLine(numbers[2]); // prints 5
Console.WriteLine(numbers[3]); // prints 7

// using foreach LINQ method


numbers.ForEach(num => Console.WriteLine(num + ", "));//prints 1, 2,
5, 7, 8, 10,

// using for loop


for(int i = 0; i < numbers.Count; i++)
Console.WriteLine(numbers[i]);
Try it

Accessing a List using LINQ


The List<T> implements the IEnumerable interface. So, we can query
a list using LINQ query syntax or method syntax, as shown below.

Example: LINQ Query on List

var students = new List<Student>() {


new Student(){ Id = 1, Name="Bill"},
new Student(){ Id = 2, Name="Steve"},
new Student(){ Id = 3, Name="Ram"},
new Student(){ Id = 4, Name="Abdul"}
};

//get all students whose name is Bill


var result = from s in students
where s.Name == "Bill"
select s;

foreach(var student in result)


Console.WriteLine(student.Id + ", " + student.Name);
Try it
ADVERTISEMENT

Insert Elements in List


Use the Insert() method inserts an element into
the List<T> collection at the specified index.

Insert() signature:void Insert(int index, T item);

Example: Insert elements into List

var numbers = new List<int>(){ 10, 20, 30, 40 };

numbers.Insert(1, 11);// inserts 11 at 1st index: after 10.

foreach (var num in numbers)


Console.Write(num);
Try it

Remove Elements from List


Use the Remove() method to remove the first occurrence of the
specified element in the List<T> collection. Use
the RemoveAt() method to remove an element from the specified
index. If no element at the specified index, then
the ArgumentOutOfRangeException will be thrown.

Remove() signature: bool Remove(T item)

RemoveAt() signature: void RemoveAt(int index)


Example: Remove elements from List

var numbers = new List<int>(){ 10, 20, 30, 40, 10 };

numbers.Remove(10); // removes the first 10 from a list

numbers.RemoveAt(2); //removes the 3rd element (index starts from 0)

//numbers.RemoveAt(10); //throws ArgumentOutOfRangeException

foreach (var el in intList)


Console.Write(el); //prints 20 30
Try it

Check Elements in List


Use the Contains() method to determine whether an element is in
the List<T> or not.

Example: Contains()

var numbers = new List<int>(){ 10, 20, 30, 40 };


numbers.Contains(10); // returns true
numbers.Contains(11); // returns false
numbers.Contains(20); // returns true
Try it

List<T> Class Hierarchy


The following diagram illustrates the List<T> hierarchy.
List<T> Class Properties and Methods
The following table lists the important properties and methods
of List<T> class:
Property Usage

Items Gets or sets the element at the specified index

Count Returns the total number of elements exists in the List<T>

Method Usage

Add Adds an element at the end of a List<T>.

AddRange Adds elements of the specified collection at the end of a List<T>.

BinarySearch Search the element and returns an index of the element.

Clear Removes all the elements from a List<T>.

Contains Checks whether the specified element exists or not in a List<T>.

Find Finds the first element based on the specified predicate function.

Foreach Iterates through a List<T>.

Insert Inserts an element at the specified index in a List<T>.

InsertRange Inserts elements of another collection at the specified index.

Remove Removes the first occurrence of the specified element.

RemoveAt Removes the element at the specified index.

RemoveRange Removes all the elements that match the supplied predicate function.

Sort Sorts all the elements.

TrimExcess Sets the capacity to the actual number of elements.

TrueForAll Determines whether every element in the List<T> matches the conditions defined by the specified predicate.

C# - SortedList<TKey, TValue>
The SortedList<TKey, TValue>, and SortedList are collection classes
that can store key-value pairs that are sorted by the keys based on
the associated IComparer implementation. For example, if the keys
are of primitive types, then sorted in ascending order of keys.
C# supports generic and non-generic SortedList. It is recommended
to use generic SortedList<TKey, TValue> because it performs faster
and less error-prone than the non-generic SortedList.

SortedList Characteristics
 SortedList<TKey, TValue> is an array of key-value pairs sorted by keys.
 Sorts elements as soon as they are added. Sorts primitive type keys in
ascending order and object keys based on IComparer<T>.
 Comes under System.Collection.Generic namespace.
 A key must be unique and cannot be null.
 A value can be null or duplicate.
 A value can be accessed by passing associated key in the
indexer mySortedList[key]
 Contains elements of type KeyValuePair<TKey, TValue>
 It uses less memory than SortedDictionary<TKey,TValue>.
 It is faster in the retrieval of data once sorted,
whereas SortedDictionary<TKey, TValue> is faster in insertion and
removing key-value pairs.

Creating a SortedList
The following example demonstrates how to create a
generic SortedList<TKey, TValue>, and add key-value pairs in it.

Example: Create a SortedList and Add Elements

//SortedList of int keys, string values


SortedList<int, string> numberNames = new SortedList<int, string>();
numberNames.Add(3, "Three");
numberNames.Add(1, "One");
numberNames.Add(2, "Two");
numberNames.Add(4, null);
numberNames.Add(10, "Ten");
numberNames.Add(5, "Five");

//The following will throw exceptions


//numberNames.Add("Three", 3); //Compile-time error: key must be int
type
//numberNames.Add(1, "One"); //Run-time exception: duplicate key
//numberNames.Add(null, "Five");//Run-time exception: key cannot be
null
Try it

In the above example, a generic SortedList<TKey, TValue> object is


created by specifying the type of keys and values it is going to store.
The SortedList<int, string> will store keys of int type and values of
string type.

The Add() method is used to add a single key-value pair in


a SortedList. Keys cannot be null or duplicate. If found, it will throw
a run-time exception. Values can be duplicate and null if the type is
nullable.

Use the collection-initializer syntax to initialize a SortedList with


multiple key-value pairs at the time of instantiating, as shown below.

//Creating a SortedList of string keys, string values


//using collection-initializer syntax
SortedList<string,string> cities = new SortedList<string,string>()
{
{"London", "UK"},
{"New York", "USA"},
{ "Mumbai", "India"},
{ "Johannesburg", "South
Africa"}
};

The SortedList rearranges key-value pairs in the ascending order of


keys as soon as a key-value pair added. The following example
displays all the keys and values using foreach loop.

Example: SortedList Elements Default Sorting Order

SortedList<int,string> numberNames = new SortedList<int,string>()


{
{3, "Three"},
{5, "Five"},
{1, "One"}
};

Console.WriteLine("---Initial key-values--");

foreach(KeyValuePair<int, string> kvp in numberNames)


Console.WriteLine("key: {0}, value: {1}", kvp.Key , kvp.Value );
numberNames.Add(6, "Six");
numberNames.Add(2, "Two");
numberNames.Add(4, "Four");

Console.WriteLine("---After adding new key-values--");

foreach(var kvp in numberNames)


Console.WriteLine("key: {0}, value: {1}", kvp.Key , kvp.Value );
Try it

Output:

---Initial key-values--

key: 1, value: One

key: 3, value: Three

key: 5, value: Five

---After adding new key-values--

key: 1, value: One

key: 2, value: Two

key: 3, value: Three

key: 4, value: Four

key: 5, value: Five

key: 6, value: Six


ADVERTISEMENT

Accessing SortedList
Specify a key in the indexer sortedList[key], to get or set a value in
the SortedList.

Example: Access SortedList Values

SortedList<int,string> numberNames = new SortedList<int,string>()


{
{3, "Three"},
{1, "One"},
{2, "Two"}
};

Console.WriteLine(numberNames[1]); //output: One


Console.WriteLine(numberNames[2]); //output: Two
Console.WriteLine(numberNames[3]); //output: Three
//Console.WriteLine(numberNames[10]); //run-time KeyNotFoundException

numberNames[2] = "TWO"; //updates value


numberNames[4] = "Four"; //adds a new key-value if a key does not
exists
Try it

Above, numberNames[10] will throw a KeyNotFoundException because


specified key 10 does not exist in a sortedlist. To prevent this
exception, use ContainsKey() or TryGetValue() methods, as shown
below.

Example: ContainsKey() and TryGetValue()

SortedList<int, string> numberNames = new SortedList<int,string>()


{
{3, "Three"},
{1, "One"},
{2, "Two"}
};
if(numberNames.ContainsKey(4)){
numberNames[4] = "four";
}

int result;
if(numberNames.TryGetValue(4, out result))
Console.WriteLine("Key: {0}, Value: {1}", 4, result);
Try it

Output:

Key:4, Value: Four

Use Keys and Values properties if you want to iterate


a SortedList using a for loop.

Example: Iterate SortedList using For Loop

SortedList<int, string> numberNames = new SortedList<int,string>()


{
{3, "Three"},
{1, "One"},
{2, "Two"}
};
for (int i = 0; i < numberNames.Count; i++)
{
Console.WriteLine("key: {0}, value: {1}", numberNames.Keys[i],
numberNames.Values[i]);
}
Try it

Output:

key: 1, value: One

key: 2, value: Two

key: 3, value: Three

Remove Elements from SortedList


Use the Remove(key) and RemoveAt(index) methods to remove key-
value pairs from a SortedList.
Example: Remove Elements

SortedList<int,string> numberNames = new SortedList<int,string>()


{
{3, "Three"},
{1, "One"},
{2, "Two"},
{5, "Five"},
{4, "Four"}
};

numberNames.Remove(1);//removes key 1 pair


numberNames.Remove(10);//removes key 1 pair, no error if not exists

numberNames.RemoveAt(0);//removes key-value pair from index 0


//numberNames.RemoveAt(10);//run-time exception:
ArgumentOutOfRangeException

foreach(var kvp in numberNames)


Console.WriteLine("key: {0}, value: {1}", kvp.Key ,
kvp.Value );
Try it

Output:

key: 3, value: Three

key: 4, value: Four

key: 5, value: Five

SortedList Class Hierarchy


The following diagram illustrates the SortedList hierarchy.
C# - Dictionary<TKey, TValue>
The Dictionary<TKey, TValue> is a generic collection that stores key-
value pairs in no particular order.

Dictionary Characteristics
 Dictionary<TKey, TValue> stores key-value pairs.
 Comes under System.Collections.Generic namespace.
 Implements IDictionary<TKey, TValue> interface.
 Keys must be unique and cannot be null.
 Values can be null or duplicate.
 Values can be accessed by passing associated key in the indexer
e.g. myDictionary[key]
 Elements are stored as KeyValuePair<TKey, TValue> objects.

Creating a Dictionary
You can create the Dictionary<TKey, TValue> object by passing the
type of keys and values it can store. The following example shows
how to create a dictionary and add key-value pairs.

Example: Create Dictionary and Add Elements

IDictionary<int, string> numberNames = new Dictionary<int, string>();


numberNames.Add(1,"One"); //adding a key/value using the Add() method
numberNames.Add(2,"Two");
numberNames.Add(3,"Three");

//The following throws run-time exception: key already added.


//numberNames.Add(3, "Three");

foreach(KeyValuePair<int, string> kvp in numberNames)


Console.WriteLine("Key: {0}, Value: {1}", kvp.Key, kvp.Value);

//creating a dictionary using collection-initializer syntax


var cities = new Dictionary<string, string>(){
{"UK", "London, Manchester, Birmingham"},
{"USA", "Chicago, New York, Washington"},
{"India", "Mumbai, New Delhi, Pune"}
};

foreach(var kvp in cities)


Console.WriteLine("Key: {0}, Value: {1}", kvp.Key, kvp.Value);
Try it

In the above example, numberNames is a Dictionary<int,


string> type dictionary, so it can store int keys and string values. In
the same way, cities is a Dictionary<string, string> type
dictionary, so it can store string keys and string values. Dictionary
cannot include duplicate or null keys, whereas values can be
duplicated or null. Keys must be unique otherwise, it will throw a
runtime exception.

Access Dictionary Elements


The Dictionary can be accessed using indexer. Specify a key to get
the associated value. You can also use the ElementAt() method to
get a KeyValuePair from the specified index.

Example: Access Dictionary Elements

var cities = new Dictionary<string, string>(){


{"UK", "London, Manchester, Birmingham"},
{"USA", "Chicago, New York, Washington"},
{"India", "Mumbai, New Delhi, Pune"}
};

Console.WriteLine(cities["UK"]); //prints value of UK key


Console.WriteLine(cities["USA"]);//prints value of USA key
//Console.WriteLine(cities["France"]); // run-time exception: Key does
not exist

//use ContainsKey() to check for an unknown key


if(cities.ContainsKey("France")){
Console.WriteLine(cities["France"]);
}

//use TryGetValue() to get a value of unknown key


string result;

if(cities.TryGetValue("France", out result))


{
Console.WriteLine(result);
}

//use ElementAt() to retrieve key-value pair using index


for (int i = 0; i < cities.Count; i++)
{
Console.WriteLine("Key: {0}, Value: {1}",
cities.ElementAt(i).Key,
cities.ElementAt(i).Value)
;
}
Try it
ADVERTISEMENT

Update Dictionary
Update the value of a key by specifying a key in the indexer. It will
throw the KeyNotFoundException if a key does not exist in the
dictionary, therefore use the ContainsKey() method before accessing
unknown keys.

Example: Update Dictionary Elements

var cities = new Dictionary<string, string>(){


{"UK", "London, Manchester, Birmingham"},
{"USA", "Chicago, New York, Washington"},
{"India", "Mumbai, New Delhi, Pune"}
};

cities["UK"] = "Liverpool, Bristol"; // update value of UK key


cities["USA"] = "Los Angeles, Boston"; // update value of USA key
//cities["France"] = "Paris"; //throws run-time exception:
KeyNotFoundException

if(cities.ContainsKey("France")){
cities["France"] = "Paris";
}
Try it

Remove Elements in Dictionary


The Remove() method deletes an existing key-value pair from a
dictionary. The Clear() method deletes all the elements of the
dictionary.

Example: Remove Dictionary Elements

var cities = new Dictionary<string, string>(){


{"UK", "London, Manchester, Birmingham"},
{"USA", "Chicago, New York, Washington"},
{"India", "Mumbai, New Delhi, Pune"}
};

cities.Remove("UK"); // removes UK
//cities.Remove("France"); //throws run-time exception:
KeyNotFoundException

if(cities.ContainsKey("France")){ // check key before removing it


cities.Remove("France");
}

cities.Clear(); //removes all elements


Try it

Dictionary Class Hierarchy


The following diagram illustrates the generic Dictionary class
hierarchy.

C# - Hashtable
The Hashtable is a non-generic collection that stores key-value pairs,
similar to generic Dictionary<TKey, TValue>  collection. It optimizes
lookups by computing the hash code of each key and stores it in a
different bucket internally and then matches the hash code of the
specified key at the time of accessing values.

Hashtable Characteristics
 Hashtable stores key-value pairs.
 Comes under System.Collection namespace.
 Implements IDictionary interface.
 Keys must be unique and cannot be null.
 Values can be null or duplicate.
 Values can be accessed by passing associated key in the indexer
e.g. myHashtable[key]
 Elements are stored as DictionaryEntry objects.

Creating a Hashtable
The following example demonstrates creating a Hashtable and adding
elements.

Example: Create and Add Elements

Hashtable numberNames = new Hashtable();


numberNames.Add(1,"One"); //adding a key/value using the Add() method
numberNames.Add(2,"Two");
numberNames.Add(3,"Three");

//The following throws run-time exception: key already added.


//numberNames.Add(3, "Three");

foreach(DictionaryEntry de in numberNames)
Console.WriteLine("Key: {0}, Value: {1}", de.Key, de.Value);

//creating a Hashtable using collection-initializer syntax


var cities = new Hashtable(){
{"UK", "London, Manchester, Birmingham"},
{"USA", "Chicago, New York, Washington"},
{"India", "Mumbai, New Delhi, Pune"}
};
foreach(DictionaryEntry de in cities)
Console.WriteLine("Key: {0}, Value: {1}", de.Key, de.Value);
Try it

The Hashtable collection can include all the elements of Dictionary, as


shown below.

Example: Add Dictionary in Hashtable

Dictionary<int, string> dict = new Dictionary<int, string>();


dict.Add(1, "one");
dict.Add(2, "two");
dict.Add(3, "three");

Hashtable ht = new Hashtable(dict);


Try it

Update Hashtable
You can retrieve the value of an existing key from the Hashtable by
passing a key in indexer. The Hashtable is a non-generic collection,
so you must type cast values while retrieving it.

Example: Update Hashtable

//creating a Hashtable using collection-initializer syntax


var cities = new Hashtable(){
{"UK", "London, Manchester, Birmingham"},
{"USA", "Chicago, New York, Washington"},
{"India", "Mumbai, New Delhi, Pune"}
};

string citiesOfUK = (string) cities["UK"]; //cast to string


string citiesOfUSA = (string) cities["USA"]; //cast to string

Console.WriteLine(citiesOfUK);
Console.WriteLine(citiesOfUSA);

cities["UK"] = "Liverpool, Bristol"; // update value of UK key


cities["USA"] = "Los Angeles, Boston"; // update value of USA key

if(!cities.ContainsKey("France")){
cities["France"] = "Paris";
}
Try it
ADVERTISEMENT

Remove Elements in Hashtable


The Remove() method removes the key-value that match with the
specified in the Hashtable. It throws the KeyNotfoundException if the
specified key not found in the Hashtable, so check for an existing key
using the ContainsKey() method before removing.

Use the Clear() method to remove all the elements in one shot.

Example: Remove Elements from Hashtable

var cities = new Hashtable(){


{"UK", "London, Manchester, Birmingham"},
{"USA", "Chicago, New York, Washington"},
{"India", "Mumbai, New Delhi, Pune"}
};

cities.Remove("UK"); // removes UK
//cities.Remove("France"); //throws run-time exception:
KeyNotFoundException

if(cities.ContainsKey("France")){ // check key before removing it


cities.Remove("France");
}

cities.Clear(); //removes all elements


Try it

Hashtable Class Hierarchy


The following diagram illustrates the Hashtable class hierarchy.
C# Hashtable

C# - Stack<T>
Stack is a special type of collection that stores elements in LIFO style
(Last In First Out). C# includes the generic Stack<T> and non-
generic Stack collection classes. It is recommended to use the
generic Stack<T> collection.

Stack is useful to store temporary data in LIFO style, and you might
want to delete an element after retrieving its value.

Stack<T> Characteristics
 Stack<T> is Last In First Out collection.
 It comes under System.Collection.Generic namespace.
 Stack<T> can contain elements of the specified type. It provides compile-
time type checking and doesn't perform boxing-unboxing because it is
generic.
 Elements can be added using the Push() method. Cannot use collection-
initializer syntax.
 Elements can be retrieved using the Pop() and the Peek() methods. It does
not support an indexer.

Creating a Stack
You can create an object of the Stack<T> by specifying a type
parameter for the type of elements it can store. The following
example creates and adds elements in the Stack<T> using
the Push() method. Stack allows null (for reference types) and
duplicate values.

Example: Create and Add Elements in Stack

Stack<int> myStack = new Stack<int>();


myStack.Push(1);
myStack.Push(2);
myStack.Push(3);
myStack.Push(4);

foreach (var item in myStack)


Console.Write(item + ","); //prints 4,3,2,1,
Try it

You can also create a Stack from an array, as shown below.


Example: Create and Add Elements in Stack

int[] arr = new int[]{ 1, 2, 3, 4};


Stack<int> myStack = new Stack<int>(arr);

foreach (var item in myStack)


Console.Write(item + ","); //prints 4,3,2,1,
Try it

Stack<T> Properties and Methods:


Property Usage

Count Returns the total count of elements in the Stack.

Method Usage

Push(T) Inserts an item at the top of the stack.

Peek() Returns the top item from the stack.

Pop() Removes and returns items from the top of the stack.

Contains(T) Checks whether an item exists in the stack or not.

Clear() Removes all items from the stack.

Pop()
The Pop() method returns the last element and removes it from a
stack. If a stack is empty, then it will throw
the InvalidOperationException. So, always check for the number of
elements in a stack before calling the Pop() method.

Example: Access Stack using Pop()

Stack<int> myStack = new Stack<int>();


myStack.Push(1);
myStack.Push(2);
myStack.Push(3);
myStack.Push(4);

Console.Write("Number of elements in Stack: {0}", myStack.Count);


while (myStack.Count > 0)
Console.Write(myStack.Pop() + ",");

Console.Write("Number of elements in Stack: {0}", myStack.Count);


Try it

Output:

Number of elements in Stack: 4

4,3,2,1,

Number of elements in Stack: 0

Peek()
The Peek() method returns the lastly added value from the stack but
does not remove it. Calling the Peek() method on an empty stack will
throw the InvalidOperationException. So, always check for elements
in the stack before retrieving elements using the Peek() method.

Example: Retrieve Elements usign Peek()

Stack<int> myStack = new Stack<int>();


myStack.Push(1);
myStack.Push(2);
myStack.Push(3);
myStack.Push(4);

Console.Write("Number of elements in Stack: {0}", myStack.Count);//


prints 4

if(myStack.Count > 0){


Console.WriteLine(myStack.Peek()); // prints 4
Console.WriteLine(myStack.Peek()); // prints 4
}

Console.Write("Number of elements in Stack: {0}", myStack.Count);//


prints 4
Try it
Contains()
The Contains() method checks whether the specified element exists
in a Stack collection or not. It returns true if it exists, otherwise
false.

Example: Contains()

Stack<int> myStack = new Stack<int>();


myStack.Push(1);
myStack.Push(2);
myStack.Push(3);
myStack.Push(4);

myStack.Contains(2); // returns true


myStack.Contains(10); // returns false

C# - Queue<T>
Queue is a special type of collection that stores the elements in FIFO
style (First In First Out), exactly opposite of the Stack<T> collection.
It contains the elements in the order they were added. C# includes
generic Queue<T> and non-generic Queue collection. It is
recommended to use the generic Queue<T> collection.

Queue<T> Characteristics
 Queue<T> is FIFO (First In First Out) collection.
 It comes under System.Collection.Generic namespace.
 Queue<T> can contain elements of the specified type. It provides compile-
time type checking and doesn't perform boxing-unboxing because it is
generic.
 Elements can be added using the Enqueue() method. Cannot use collection-
initializer syntax.
 Elements can be retrieved using the Dequeue() and the Peek() methods. It
does not support an indexer.

The following figure illustrates the Queue collection:


Creating a Queue
You can create an object of the Queue<T> by specifying a type
parameter for the type of elements it can store. The following
example creates and adds elements in the Queue<T> using
the Enqueue() method. A Queue collection allows null (for reference
types) and duplicate values.

Example: Create and Add Elements in the Queue

Queue<int> callerIds = new Queue<int>();


callerIds.Enqueue(1);
callerIds.Enqueue(2);
callerIds.Enqueue(3);
callerIds.Enqueue(4);

foreach(var id in callerIds)
Console.Write(id); //prints 1234
Try it

Queue<T> Properties and Methods


Property Usage

Count Returns the total count of elements in the Queue.

Method Usage

Enqueue(T) Adds an item into the queue.

Dequeue Returns an item from the beginning of the queue and removes it from the queue.
Method Usage

Peek(T) Returns an first item from the queue without removing it.

Contains(T) Checks whether an item is in the queue or not

Clear() Removes all the items from the queue.

Retrieve Elements from a Queue


The Dequeue() and the Peek() method is used to retrieve the first
element in a queue collection. The Dequeue() removes and returns
the first element from a queue because the queue stores elements in
FIFO order. Calling the Dequeue() method on an empty queue will
throw the InvalidOperation exception. So, always check that the
total count of a queue is greater than zero before calling it.

Example: Reading Queue

Queue<string> strQ = new Queue<string>();


strQ.Enqueue("H");
strQ.Enqueue("e");
strQ.Enqueue("l");
strQ.Enqueue("l");
strQ.Enqueue("o");

Console.WriteLine("Total elements: {0}", strQ.Count); //prints 5

while (strQ.Count > 0)


Console.WriteLine(strQ.Dequeue()); //prints Hello

Console.WriteLine("Total elements: {0}", strQ.Count); //prints 0


Try it

The Peek() method always returns the first item from a queue


collection without removing it from the queue. Calling
the Peek() method on an empty queue will throw a run-time
exception InvalidOperationException.

Example: Peek()

Queue<string> strQ = new Queue<string>();


strQ.Enqueue("H");
strQ.Enqueue("e");
strQ.Enqueue("l");
strQ.Enqueue("l");
strQ.Enqueue("o");

Console.WriteLine("Total elements: {0}", strQ.Count); //prints 5

if(strQ.Count > 0){


Console.WriteLine(strQ.Peek()); //prints H
Console.WriteLine(strQ.Peek()); //prints H
}

Console.WriteLine("Total elements: {0}", strQ.Count); //prints 0


Try it

Contains()
The Contains() method checks whether an item exists in a queue or
not. It returns true if the specified item exists, otherwise returns
false.

Contains() Signature: bool Contains(object obj);

Example: Contains()

Queue<int> callerIds = new Queue<int>();


callerIds.Enqueue(1);
callerIds.Enqueue(2);
callerIds.Enqueue(3);
callerIds.Enqueue(4);

callerIds.Contains(2); //true
callerIds.Contains(10); //false

C# - Tuple
The Tuple<T> class was introduced in .NET Framework 4.0. A tuple is
a data structure that contains a sequence of elements of different
data types. It can be used where you want to have a data structure
to hold an object with properties, but you don't want to create a
separate type for it.
Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>

The following example creates a tuple with three elements:

Tuple<int, string, string> person =


new Tuple <int, string, string>(1, "Steve",
"Jobs");

In the above example, we created an instance of the Tuple that holds


a person's record. We specified a type for each element and passed
values to the constructor. Specifying the type of each element is
cumbersome. C# includes a static helper class Tuple, which returns
an instance of the Tuple<T> without specifying each element's type,
as shown below.

var person = Tuple.Create(1, "Steve", "Jobs");

A tuple can only include a maximum of eight elements. It gives a


compiler error when you try to include more than eight elements.

var numbers = Tuple.Create(1, 2, 3, 4, 5, 6, 7, 8);

Accessing Tuple Elements


A tuple elements can be accessed
with Item<elementNumber> properties, e.g., Item1, Item2, Item3, and
so on up to Item7 property. The Item1 property returns the first
element, Item2 returns the second element, and so on. The last
element (the 8th element) will be returned using the Rest property.

Example: Accessing Tuple Elements

var person = Tuple.Create(1, "Steve", "Jobs");


person.Item1; // returns 1
person.Item2; // returns "Steve"
person.Item3; // returns "Jobs"

var numbers = Tuple.Create("One", 2, 3, "Four", 5, "Six", 7, 8);


numbers.Item1; // returns "One"
numbers.Item2; // returns 2
numbers.Item3; // returns 3
numbers.Item4; // returns "Four"
numbers.Item5; // returns 5
numbers.Item6; // returns "Six"
numbers.Item7; // returns 7
numbers.Rest; // returns (8)
numbers.Rest.Item1; // returns 8
Try it

Generally, the 8th position is for the nested tuple, which you can
access using the Rest property.

Nested Tuples
If you want to include more than eight elements in a tuple, you can
do that by nesting another tuple object as the eighth element. The
last nested tuple can be accessed using the Rest property. To access
the nested tuple's element, use
the Rest.Item1.Item<elelementNumber> property.

Example: Nested Tuple

var numbers = Tuple.Create(1, 2, 3, 4, 5, 6, 7, Tuple.Create(8, 9, 10,


11, 12, 13));
numbers.Item1; // returns 1
numbers.Item7; // returns 7
numbers.Rest.Item1; //returns (8, 9, 10, 11, 12, 13)
numbers.Rest.Item1.Item1; //returns 8
numbers.Rest.Item1.Item2; //returns 9
Try it

You can include the nested tuple object anywhere in the sequence.
However, it is recommended to place the nested tuple at the end of
the sequence so that it can be accessed using the Rest property.

Example: Nested Tuple

var numbers = Tuple.Create(1, 2, Tuple.Create(3, 4, 5, 6, 7, 8), 9,


10, 11, 12, 13 );
numbers.Item1; // returns 1
numbers.Item2; // returns 2
numbers.Item3; // returns (3, 4, 5, 6, 7, 8)
numbers.Item3.Item1; // returns 3
numbers.Item4; // returns 9
numbers.Rest.Item1; //returns 13
Try it
ADVERTISEMENT

Tuple as a Method Parameter


A method can have a tuple as a parameter.

static void Main(string[] args)


{
var person = Tuple.Create(1, "Steve", "Jobs");
DisplayTuple(person);
}

static void DisplayTuple(Tuple<int,string,string> person)


{
Console.WriteLine($"Id = { person.Item1}");
Console.WriteLine($"First Name = { person.Item2}");
Console.WriteLine($"Last Name = { person.Item3}");
}

Tuple as a Return Type


A Tuple can be return from a method.

static void Main(string[] args)


{
var person = GetPerson();
}

static Tuple<int, string, string> GetPerson()


{
return Tuple.Create(1, "Bill", "Gates");
}

Usage of Tuple
Tuples can be used in the following scenarios:

1. When you want to return multiple values from a method without


using ref or out parameters.
2. When you want to pass multiple values to a method through a single
parameter.
3. When you want to hold a database record or some values temporarily
without creating a separate class.

Tuple Limitations:
1. The Tuple is a reference type and not a value type. It allocates on heap and
could result in CPU intensive operations.
2. The Tuple is limited to include eight elements. You need to use nested
tuples if you need to store more elements. However, this may result in
ambiguity.
3. The Tuple elements can be accessed using properties with a name
pattern Item<elementNumber>, which does not make sense.

C# 7 includes ValueTuple to overcome Tuple's limitations and makes


it even easier to work with Tuple.

C# - ValueTuple
C# 7.0 (.NET Framework 4.7) introduced the ValueTuple structure,
which is a value type representation of the Tuple.

The ValueTuple is only available in .NET Framework 4.7. If you don't


see ValueTuple in your project, then you need to install the
ValueTuple. (.NET Framework 4.7 or higher, or .NET Standard Library
2.0 or higher already includes ValueTuple.)

To install the ValueTuple package, right-click on the project in the


solution explorer and select Manage NuGet Packages... This will
open the NuGet Package Manager. Click the Browse tab, search for
ValueTuple in the search box, and select
the System.ValueTuple package, as shown below.
ValueTuple Initialization
It is easy to create and initialize the ValueTuple. It can be created
and initialized using parentheses () and specifying the values in it.

var person = (1, "Bill", "Gates");

//equivalent Tuple
//var person = Tuple.Create(1, "Bill", "Gates");

The ValueTuple can also be initialized by specifying the type of each


element, as shown below.
ValueTuple<int, string, string> person = (1, "Bill", "Gates");
person.Item1; // returns 1
person.Item2; // returns "Bill"
person.Item3; // returns "Gates"

The following is a short way of declaring types for each member.

(int, string, string) person = (1, "Bill", "Gates");


person.Item1; // returns 1
person.Item2; // returns "Bill"
person.Item3; // returns "Gates"

Please notice that we have not used var in the above tuple


initialization statement; instead, we provided the type of each
member values inside the brackets.

Tuple requires at least two values. The following is NOT a tuple.

var number = (1); // int type, NOT a tuple


var numbers = (1,2); //valid tuple

Unlike Tuple, a ValueTuple can include more than eight values.

var numbers = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);

Named Members
We can assign names to the ValueTuple properties instead of having
the default property names like Item1, Item2 and so on.

(int Id, string FirstName, string LastName) person = (1, "Bill",


"Gates");
person.Id; // returns 1
person.FirstName; // returns "Bill"
person.LastName; // returns "Gates"

We can also assign member names on the right side with values, as
below.

var person = (Id:1, FirstName:"Bill", LastName: "Gates");


Please note that we can provide member names either on the left or
right sides but not on both sides. The left side has precedence over
the right side. The following will ignore names on the right side.

// PersonId, FName, LName will be ignored.


(int Id, string FirstName, string LastName) person = (PersonId:1,
FName:"Bill", LName: "Gates");

// PersonId, FirstName, LastName will be ignored. It will have the


default names: Item1, Item2, Item3.
(string, string, int) person = (PersonId:1, FName:"Bill", LName:
"Gates");

We can also assign variables as member values.

string firstName = "Bill", lastName = "Gates";


var per = (FirstName: firstName, LastName: lastName);
ADVERTISEMENT

ValueTuple as Return Type


The following method returns a ValueTuple.

static void Main(string[] args)


{
DisplayTuple(1, "Bill", "Gates");
}

static void DisplayTuple((int, string, string) person)


{
Console.WriteLine($"Id = { person.Item1}");
Console.WriteLine($"First Name = { person.Item2}");
Console.WriteLine($"Last Name = { person.Item3}");
}

We can also specify different member names for


a ValueTuple returned from a method.

static void Main(string[] args)


{
var person = GetPerson();
}

static (int, string, string) GetPerson()


{
return (Id:1, FirstName: "Bill", LastName: "Gates");
}

Deconstruction
Individual members of a ValueTuple can be retrieved by
deconstructing it. A deconstructing declaration syntax splits
a ValueTuple into its parts and assigns those parts individually to
fresh variables.

static void Main(string[] args)


{
// change property names
(int PersonId, string FName, string LName) = GetPerson();
}
static (int, string, string) GetPerson()
{
return (Id:1, FirstName: "Bill", LastName: "Gates");
}

We can also use var instead of explicit data type names.

static void Main(string[] args)


{
// use var as datatype
(var PersonId, var FName, var LName) person = GetPerson();
}
static (int, string, string) GetPerson()
{
return (Id:1, FirstName: "Bill", LastName: "Gates");
}

ValueTuple also allows "discards" in deconstruction for the members


you are not going to use.

// use discard _ for the unused member LName


(var id, var FName, _) = GetPerson();

Built-in Exception Classes in C#


Here you will learn about the built-in exception classes in C#.

C# .NET includes built-in exception classes for every possible error.


The Exception class is the base class of all the exception classes.

The following is a hierarchy of exception classes in .NET:

Exception Classes in .NET

In the above figure, the Exception class is the base class of


the SystemException and ApplicationException classes.
The SystemException class is the base class for all the exceptions that
can occur during the execution of the program.
The ApplicationException class should be derive to create your own
custom exception class. The custom exeception class can be created
for business rule violations or for other application related errors.

The following figure shows how the NullReferenceException is thrown


in Visual Studio debug mode when you access a null object property
at runtime.
Nul
lReferenceException

Built-in Exception Classes


The following table lists important built-in exception classes in .NET.

Exception Class Description

ArgumentException Raised when a non-null argument that is passed to a method is invalid.

ArgumentNullException Raised when null argument is passed to a method.

ArgumentOutOfRangeException Raised when the value of an argument is outside the range of valid values.

DivideByZeroException Raised when an integer value is divide by zero.

FileNotFoundException Raised when a physical file does not exist at the specified location.

FormatException Raised when a value is not in an appropriate format to be converted from a string by a
conversion method such as Parse.

IndexOutOfRangeException Raised when an array index is outside the lower or upper bounds of an array or collection.

InvalidOperationException Raised when a method call is invalid in an object's current state.

KeyNotFoundException Raised when the specified key for accessing a member in a collection is not exists.

NotSupportedException Raised when a method or operation is not supported.

NullReferenceException Raised when program access members of null object.

OverflowException Raised when an arithmetic, casting, or conversion operation results in an overflow.

OutOfMemoryException Raised when a program does not get enough memory to execute the code.
Exception Class Description

StackOverflowException Raised when a stack in memory overflows.

TimeoutException The time interval allotted to an operation has expired.

When an error occurs, either the application code or the default


handler handles the exception.

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.

The following may throw an exception if you enter a non-numeric


character.

Example: C# Program

class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter a number: ");

var num = int.Parse(Console.ReadLine());

Console.WriteLine($"Squre of {num} is {num * num}");


}
}
Try it

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.

Example: Exception handling using try-catch blocks

class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Enter a number: ");

var num = int.parse(Console.ReadLine());

Console.WriteLine($"Squre of {num} is {num * num}");


}
catch
{
Console.Write("Error occurred.");
}
finally
{
Console.Write("Re-try with a different number.");
}
}
}
Try it

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.

Example: Exception handling using try catch block

class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Enter a number: ");

var num = int.parse(Console.ReadLine());

Console.WriteLine($"Squre of {num} is {num * num}");


}
catch(Exception ex)
{
Console.Write("Error info:" + ex.Message);
}
finally
{
Console.Write("Re-try with a different number.");
}
}
}

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.

Example: Exception Filters


class Program
{
static void Main(string[] args)
{
Console.Write("Please enter a number to divide 100: ");

try
{
int num = int.Parse(Console.ReadLine());

int result = 100 / num;

Console.WriteLine("100 / {0} = {1}", num, result);


}
catch(DivideByZeroException ex)
{
Console.Write("Cannot divide by zero. Please try again.");
}
catch(InvalidOperationException ex)
{
Console.Write("Invalid operation. Please try again.");
}
catch(FormatException ex)
{
Console.Write("Not a valid format. Please try again.");
}
catch(Exception ex)
{
Console.Write("Error occurred! Please try again.");
}
}

}
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

Invalid catch Block


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.

Example: Invalid catch

try
{
//code that may raise an exception
}
catch //cannot have both catch and catch(Exception ex)
{
Console.WriteLine("Exception occurred");
}
catch(Exception ex) //cannot have both catch and catch(Exception ex)
{
Console.WriteLine("Exception occurred");
}

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.

Example: Invalid catch


try
{
//code that may raise an exception
}
catch
{
// this catch block must be last block
}
catch (NullReferenceException nullEx)
{
Console.WriteLine(nullEx.Message);
}
catch (InvalidCastException inEx)
{
Console.WriteLine(inEx.Message);
}

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.

Example: finally Block

static void Main(string[] args)


{
FileInfo file = null;

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.

Example: Nested try-catch

static void Main(string[] args)


{
var divider = 0;

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.

Example: Nested try-catch

static void Main(string[] args)


{
var divider = 0;

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.

Example: throw an exception

static void Main(string[] args)


{
Student std = null;

try
{
PrintStudentName(std);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message );
}

Console.ReadKey();
}

private static void PrintStudentName( Student std)


{
if (std == null)
throw new NullReferenceException("Student object is null.");

Console.WriteLine(std.StudentName);
}
Try it

Output:

Student object is null.


In the above example, PrintStudentName() method raises
NullReferenceException if Student object is null.

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.

Example: throw an exception

static void Main(string[] args)


{
try
{
Method1();
}
catch(Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
}

static void Method1()


{
try
{
Method2();
}
catch(Exception ex)
{
throw;
}
}

static void Method2()


{
string str = null;
try
{
Console.WriteLine(str[0]);
}
catch(Exception ex)
{
throw;
}
}
Try it

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.

Example: throw an exception

static void Main(string[] args)


{
try
{
Method1();
}
catch(Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
}

static void Method1()


{
try
{
Method2();
}
catch(Exception ex)
{
throw ex;
}
}

static void Method2()


{
string str = null;
try
{
Console.WriteLine(str[0]);
}
catch(Exception ex)
{
throw;
}
}
Try it

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>.

Custom Exception Type in C#


C# includes the built-in exception types such
as NullReferenceException, MemoryOverflowException, etc. However,
you often like to raise an exception when the business rule of your
application gets violated. So, for this, you can create a custom
exception class by deriving the ApplicationException class.

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.

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()
{

public InvalidStudentNameException(string name)


: base(String.Format("Invalid Student Name: {0}", name))
{

Now, you can raise InvalidStudentNameException in your program


whenever the name contains special characters or numbers. Use
the throw keyword to raise an exception.

Example: throw custom exception

class Program
{
static void Main(string[] args)
{
Student newStudent = null;

try
{
newStudent = new Student();
newStudent.StudentName = "James007";

ValidateStudent(newStudent);
}
catch(InvalidStudentNameException ex)
{
Console.WriteLine(ex.Message );
}
Console.ReadKey();
}

private static void ValidateStudent(Student std)


{
Regex regex = new Regex("^[a-zA-Z]+$");

if (!regex.IsMatch(std.StudentName))
throw new InvalidStudentNameException(std.StudentName);

}
}
Output:

Invalid Student Name: James000

Thus, you can create custom exception classes to differentiate from


system exceptions.

C# - Delegates
What if we want to pass a function as a parameter? How does C#
handles the callback functions or event handler? The answer is -
delegate.

The delegate is a reference type data type that defines the method


signature. You can define variables of delegate, just like other data
type, that can refer to any method with the same signature as the
delegate.

There are three steps involved while working with delegates:

1. Declare a delegate
2. Set a target method
3. Invoke a delegate

A delegate can be declared using the delegate keyword followed by a


function signature, as shown below.

Delegate Syntax
[access modifier] delegate [return type] [delegate name]([parameters])

The following declares a delegate named MyDelegate.

Example: Declare a Delegate

public delegate void MyDelegate(string msg);

Above, we have declared a delegate MyDelegate with a void return


type and a string parameter. A delegate can be declared outside of
the class or inside the class. Practically, it should be declared out of
the class.

After declaring a delegate, we need to set the target method or


a lambda expression. We can do it by creating an object of the
delegate using the new keyword and passing a method whose
signature matches the delegate signature.

Example: Set Delegate Target

public delegate void MyDelegate(string msg); // declare a delegate

// set target method


MyDelegate del = new MyDelegate(MethodA);
// or
MyDelegate del = MethodA;
// or set lambda expression
MyDelegate del = (string msg) => Console.WriteLine(msg);

// target method
static void MethodA(string message)
{
Console.WriteLine(message);
}

You can set the target method by assigning a method directly


without creating an object of delegate e.g., MyDelegate del =
MethodA.

After setting a target method, a delegate can be invoked using


the Invoke() method or using the () operator.

Example: Invoke a Delegate


del.Invoke("Hello World!");
// or
del("Hello World!");

The following is a full example of a delegate.

Example: Delegate

public delegate void MyDelegate(string msg); //declaring a delegate

class Program
{
static void Main(string[] args)
{
MyDelegate del = ClassA.MethodA;
del("Hello World");

del = ClassB.MethodB;
del("Hello World");

del = (string msg) => Console.WriteLine("Called lambda


expression: " + msg);
del("Hello World");
}
}

class ClassA
{
static void MethodA(string message)
{
Console.WriteLine("Called ClassA.MethodA() with parameter: " +
message);
}
}

class ClassB
{
static void MethodB(string message)
{
Console.WriteLine("Called ClassB.MethodB() with parameter: " +
message);
}
}
Try it
The following image illustrates the delegate.

C#
Delegate

Passing Delegate as a Parameter


A method can have a parameter of the delegate type, as shown
below.

Example: Delegate

public delegate void MyDelegate(string msg); //declaring a delegate

class Program
{
static void Main(string[] args)
{
MyDelegate del = ClassA.MethodA;
InvokeDelegate(del);

del = ClassB.MethodB;
InvokeDelegate(del);

del = (string msg) => Console.WriteLine("Called lambda


expression: " + msg);
InvokeDelegate(del);
}

static void InvokeDelegate(MyDelegate del) // MyDelegate type


parameter
{
del("Hello World");
}
}

class ClassA
{
static void MethodA(string message)
{
Console.WriteLine("Called ClassA.MethodA() with parameter: " +
message);
}
}

class ClassB
{
static void MethodB(string message)
{
Console.WriteLine("Called ClassB.MethodB() with parameter: " +
message);
}
}
Try it

 Note:

In .NET, Func and Action types are built-in generic delegates that should be used


for most common delegates instead of creating new custom delegates.
ADVERTISEMENT

Multicast Delegate
The delegate can point to multiple methods. A delegate that points
multiple methods is called a multicast delegate. The "+" or "+="
operator adds a function to the invocation list, and the "-" and "-="
operator removes it.

Example: Multicast Delegate


public delegate void MyDelegate(string msg); //declaring a delegate

class Program
{
static void Main(string[] args)
{
MyDelegate del1 = ClassA.MethodA;
MyDelegate del2 = ClassB.MethodB;

MyDelegate del = del1 + del2; // combines del1 + del2


del("Hello World");

MyDelegate del3 = (string msg) => Console.WriteLine("Called


lambda expression: " + msg);
del += del3; // combines del1 + del2 + del3
del("Hello World");

del = del - del2; // removes del2


del("Hello World");

del -= del1 // removes del1


del("Hello World");
}
}

class ClassA
{
static void MethodA(string message)
{
Console.WriteLine("Called ClassA.MethodA() with parameter: " +
message);
}
}

class ClassB
{
static void MethodB(string message)
{
Console.WriteLine("Called ClassB.MethodB() with parameter: " +
message);
}
}
Try it
The addition and subtraction operators always work as part of the
assignment: del1 += del2; is exactly equivalent to del1 =
del1+del2; and likewise for subtraction.

If a delegate returns a value, then the last assigned target method's


value will be return when a multicast delegate called.

Example: Multicast Delegate Returning a Value

public delegate int MyDelegate(); //declaring a delegate

class Program
{
static void Main(string[] args)
{
MyDelegate del1 = ClassA.MethodA;
MyDelegate del2 = ClassB.MethodB;

MyDelegate del = del1 + del2;


Console.WriteLine(del());// returns 200
}
}

class ClassA
{
static int MethodA()
{
return 100;
}
}

class ClassB
{
static int MethodB()
{
return 200;
}
}
Try it
Generic Delegate
A generic delegate can be defined the same way as a delegate but
using generic type parameters or return type. The generic type must
be specified when you set a target method.

For example, consider the following generic delegate that is used for
int and string parameters.

Example: Generic Delegate

public delegate T add<T>(T param1, T param2); // generic delegate

class Program
{
static void Main(string[] args)
{
add<int> sum = Sum;
Console.WriteLine(sum(10, 20));

add<string> con = Concat;


Console.WriteLine(conct("Hello ","World!!"));
}

public static int Sum(int val1, int val2)


{
return val1 + val2;
}

public static string Concat(string str1, string str2)


{
return str1 + str2;
}
}
Try it

Delegate is also used to declare an Event and an Anonymous Method.

Learn more about delegate here.

 Points to Remember :

1. Delegate is the reference type data type that defines the signature.
2. Delegate type variable can refer to any method with the same signature as
the delegate.
3. Syntax: [access modifier] delegate [return type] [delegate name]
([parameters])
4. A target method's signature must match with delegate signature.
5. Delegates can be invoke like a normal function or Invoke() method.
6. Multiple methods can be assigned to the delegate using "+" or "+="
operator and removed using "-" or "-=" operator. It is called multicast delegate.
7. If a multicast delegate returns a value then it returns the value from the
last assigned target method.
8. Delegate is used to declare an event and anonymous methods in C#.

C# - Func Delegate
C# includes built-in generic delegate types Func and Action, so that
you don't need to define custom delegates manually in most cases.

Func is a generic delegate included in the System namespace. It has


zero or more input parameters and one out parameter. The last
parameter is considered as an out parameter.

The Func delegate that takes one input parameter and one out


parameter is defined in the System namespace, as shown below:

Signature: Func

namespace System
{
public delegate TResult Func<in T, out TResult>(T arg);
}

The last parameter in the angle brackets <> is considered the return


type, and the remaining parameters are considered input parameter
types, as shown in the following figure.
Func delegate

A Func delegate with two input parameters and one out parameters
will be represented as shown below.

Func delegate

The following Func delegate takes two input parameters of int type


and returns a value of int type:

Func<int, int, int> sum;

You can assign any method to the above func delegate that takes
two int parameters and returns an int value.

Example: Func

class Program
{
static int Sum(int x, int y)
{
return x + y;
}

static void Main(string[] args)


{
Func<int,int, int> add = Sum;

int result = add(10, 10);


Console.WriteLine(result);
}
}
Try it

Output:

20

A Func delegate type can include 0 to 16 input parameters of


different types. However, it must include an out parameter for the
result. For example, the following Func delegate doesn't have any
input parameter, and it includes only an out parameter.

Example: Func with Zero Input Parameter

Func<int> getRandomNumber;

C# Func with an Anonymous Method


You can assign an anonymous method to the Func delegate by using
the delegate keyword.

Example: Func with Anonymous Method

Func<int> getRandomNumber = delegate()


{
Random rnd = new Random();
return rnd.Next(1, 100);
};

Func with Lambda Expression


A Func delegate can also be used with a lambda expression, as
shown below:

Example: Func with lambda expression

Func<int> getRandomNumber = () => new Random().Next(1, 100);


//Or

Func<int, int, int> Sum = (x, y) => x + y;


Try it

 Points to Remember :

1. Func is built-in delegate type.


2. Func delegate type must return a value.
3. Func delegate type can have zero to 16 input parameters.
4. Func delegate does not allow ref and out parameters.
5. Func delegate type can be used with an anonymous method or lambda
expression.

C# - Action Delegate
Action is a delegate type defined in the System namespace. An Action
type delegate is the same as Func delegate  except that the Action
delegate doesn't return a value. In other words, an Action delegate
can be used with a method that has a void return type.

For example, the following delegate prints an int value.

Example: C# Delegate

public delegate void Print(int val);

static void ConsolePrint(int i)


{
Console.WriteLine(i);
}

static void Main(string[] args)


{
Print prnt = ConsolePrint;
prnt(10);
}
Output:

10
You can use an Action delegate instead of defining the above Print
delegate, for example:

Example: Action delegate

static void ConsolePrint(int i)


{
Console.WriteLine(i);
}

static void Main(string[] args)


{
Action<int> printActionDel = ConsolePrint;
printActionDel(10);
}
Try it

You can initialize an Action delegate using the new keyword or by


directly assigning a method:

Action<int> printActionDel = ConsolePrint;

//Or

Action<int> printActionDel = new Action<int>(ConsolePrint);

An Action delegate can take up to 16 input parameters of different


types.

An Anonymous method can also be assigned to an Action delegate,


for example:

Example: Anonymous method with Action delegate

static void Main(string[] args)


{
Action<int> printActionDel = delegate(int i)
{
Console.WriteLine(i);
};

printActionDel(10);
}
Try it
Output:

10

A Lambda expression also can be used with an Action delegate:

Example: Lambda expression with Action delegate

static void Main(string[] args)


{

Action<int> printActionDel = i => Console.WriteLine(i);

printActionDel(10);
}
Try it

Thus, you can use any method that doesn't return a value with
Action delegate types.

Advantages of Action and Func Delegates


1. Easy and quick to define delegates.
2. Makes code short.
3. Compatible type throughout the application.

 Points to Remember :

1. Action delegate is same as func delegate except that it does not return
anything. Return type must be void.
2. Action delegate can have 0 to 16 input parameters.
3. Action delegate can be used with anonymous methods or lambda
expressions.

C# - Predicate Delegate
Predicate is the delegate like Func and Action delegates. It
represents a method containing a set of criteria and checks whether
the passed parameter meets those criteria. A predicate delegate
methods must take one input parameter and return a boolean - true
or false.

The Predicate delegate is defined in the System namespace, as


shown below:

Predicate signature: public delegate bool Predicate<in T>(T obj);

Same as other delegate types, Predicate can also be used with any


method, anonymous method, or lambda expression.

Example: Predicate delegate


static bool IsUpperCase(string str)
{
return str.Equals(str.ToUpper());
}

static void Main(string[] args)


{
Predicate<string> isUpper = IsUpperCase;

bool result = isUpper("hello world!!");

Console.WriteLine(result);
}
Try it
Output:

false

An anonymous method can also be assigned to a Predicate delegate


type as shown below.

Example: Predicate delegate with anonymous method


static void Main(string[] args)
{
Predicate<string> isUpper = delegate(string s) { return
s.Equals(s.ToUpper());};
bool result = isUpper("hello world!!");
}
Try it
A lambda expression can also be assigned to a Predicate delegate
type as shown below.

Example: Predicate delegate with lambda expression


static void Main(string[] args)
{
Predicate<string> isUpper = s => s.Equals(s.ToUpper());
bool result = isUpper("hello world!!");
}
Try it
 Points to Remember:

1. Predicate delegate takes one input parameter and boolean return


type.
2. Anonymous method and Lambda expression can be assigned to the
predicate delegate.

C# - Anonymous Method
As the name suggests, an anonymous method is a method without a
name. Anonymous methods in C# can be defined using the delegate
keyword and can be assigned to a variable of delegate type.

Example: Anonymous Method

public delegate void Print(int value);

static void Main(string[] args)


{
Print print = delegate(int val) {
Console.WriteLine("Inside Anonymous method. Value: {0}", val);
};

print(100);
}
Try it

Output:

Inside Anonymous method. Value: 100


Anonymous methods can access variables defined in an outer
function.

Example: Anonymous Method

public delegate void Print(int value);

static void Main(string[] args)


{
int i = 10;

Print prnt = delegate(int val) {


val += i;
Console.WriteLine("Anonymous method: {0}", val);
};

prnt(100);
}
Try it

Output:

Anonymous method: 110

Anonymous methods can also be passed to a method that accepts


the delegate as a parameter.

In the following example, PrintHelperMethod() takes the first


parameters of the Print delegate:

Example: Anonymous Method as Parameter

public delegate void Print(int value);

class Program
{
public static void PrintHelperMethod(Print printDel,int val)
{
val += 10;
printDel(val);
}

static void Main(string[] args)


{
PrintHelperMethod(delegate(int val)
{ Console.WriteLine("Anonymous method: {0}", val); }, 100);
}
}
Try it

Output:

Anonymous method: 110

Anonymous methods can be used as event handlers:

Example: Anonymous Method as Event Handler

saveButton.Click += delegate(Object o, EventArgs e)


{
System.Windows.Forms.MessageBox.Show("Save Successfully!");
};

C# 3.0 introduced the lambda expression  which also works like an


anonymous method.

Anonymous Method Limitations


 It cannot contain jump statement like goto, break or continue.
 It cannot access ref or out parameter of an outer method.
 It cannot have or access unsafe code.
 It cannot be used on the left side of the is operator.

 Points to Remember :

1. Anonymous method can be defined using the delegate keyword


2. Anonymous method must be assigned to a delegate.
3. Anonymous method can access outer variables or functions.
4. Anonymous method can be passed as a parameter.
5. Anonymous method can be used as event handlers.
C# - Events
An event is a notification sent by an object to signal the occurrence
of an action. Events in .NET follow the observer design pattern.

The class who raises events is called Publisher, and the class who
receives the notification is called Subscriber. There can be multiple
subscribers of a single event. Typically, a publisher raises an event
when some action occurred. The subscribers, who are interested in
getting a notification when an action occurred, should register with
an event and handle it.

In C#, an event is an encapsulated delegate. It is dependent on the


delegate. The delegate defines the signature for the event handler
method of the subscriber class.

The following figure illustrates the event in C#.

Event
Publisher & Subscriber

Declare an Event
An event can be declared in two steps:

1. Declare a delegate.
2. Declare a variable of the delegate with event keyword.

The following example shows how to declare an event in publisher


class.

Example: Declaring an Event

public delegate void Notify(); // delegate

public class ProcessBusinessLogic


{
public event Notify ProcessCompleted; // event

In the above example, we declared a delegate Notify and then


declared an event ProcessCompleted of delegate type Notify using
"event" keyword in the ProcessBusinessLogic class. Thus,
the ProcessBusinessLogic class is called the publisher.
The Notify delegate specifies the signature for
the ProcessCompleted event handler. It specifies that the event
handler method in subscriber class must have a void return type and
no parameters.

Now, let's see how to raise the ProcessCompleted event. Consider the


following implementation.

Example: Raising an Event

public delegate void Notify(); // delegate

public class ProcessBusinessLogic


{
public event Notify ProcessCompleted; // event

public void StartProcess()


{
Console.WriteLine("Process Started!");
// some code here..
OnProcessCompleted();
}

protected virtual void OnProcessCompleted() //protected virtual


method
{
//if ProcessCompleted is not null then call delegate
ProcessCompleted?.Invoke();
}
}

Above, the StartProcess() method calls the


method onProcessCompleted() at the end, which raises an event.
Typically, to raise an event, protected and virtual method should be
defined with the name On<EventName>. Protected and virtual enable
derived classes to override the logic for raising the event. However, A
derived class should always call the On<EventName> method of the
base class to ensure that registered delegates receive the event.

The OnProcessCompleted() method invokes the delegate


using ProcessCompleted?.Invoke();. This will call all the event
handler methods registered with the ProcessCompleted event.

The subscriber class must register to ProcessCompleted event and


handle it with the method whose signature matches Notify delegate,
as shown below.

Example: Consume an Event

class Program
{
public static void Main()
{
ProcessBusinessLogic bl = new ProcessBusinessLogic();
bl.ProcessCompleted += bl_ProcessCompleted; // register with
an event
bl.StartProcess();
}

// event handler
public static void bl_ProcessCompleted()
{
Console.WriteLine("Process Completed!");
}
}
Try it
Above, the Program class is a subscriber of
the ProcessCompleted event. It registers with the event using +=
operator. Remember, this is the same way we add methods in the
invocation list of multicast delegate.
The bl_ProcessCompleted() method handles the event because it
matches the signature of the Notify delegate.

Built-in EventHandler Delegate


.NET Framework includes built-in delegate
types EventHandler and EventHandler<TEventArgs> for the most
common events. Typically, any event should include two parameters:
the source of the event and event data. Use
the EventHandler delegate for all events that do not include event
data. Use EventHandler<TEventArgs> delegate for events that
include data to be sent to handlers.

The example shown above can use EventHandler delegate without


declaring a custom Notify delegate, as shown below.

Example: EventHandler

class Program
{
public static void Main()
{
ProcessBusinessLogic bl = new ProcessBusinessLogic();
bl.ProcessCompleted += bl_ProcessCompleted; // register with
an event
bl.StartProcess();
}

// event handler
public static void bl_ProcessCompleted(object sender, EventArgs e)
{
Console.WriteLine("Process Completed!");
}
}

public class ProcessBusinessLogic


{
// declaring an event using built-in EventHandler
public event EventHandler ProcessCompleted;

public void StartProcess()


{
Console.WriteLine("Process Started!");
// some code here..
OnProcessCompleted(EventArgs.Empty); //No event data
}

protected virtual void OnProcessCompleted(EventArgs e)


{
ProcessCompleted?.Invoke(this, e);
}
}
Try it

In the above example, the event


handler bl_ProcessCompleted() method includes two parameters that
match with EventHandler delegate. Also, passing this as a sender
and EventArgs.Empty, when we raise an event using Invoke() in
the OnProcessCompleted() method. Because we don't need any data
for our event, it just notifies subscribers about the completion of the
process, and so we passed EventArgs.Empty.
ADVERTISEMENT

Passing an Event Data


Most events send some data to the subscribers. The EventArgs class
is the base class for all the event data classes. .NET includes many
built-in event data classes such as SerialDataReceivedEventArgs. It
follows a naming pattern of ending all event data classes with
EventArgs. You can create your custom class for event data by
deriving EventArgs class.

Use EventHandler<TEventArgs> to pass data to the handler, as


shown below.

Example: Passing Event Data

class Program
{
public static void Main()
{
ProcessBusinessLogic bl = new ProcessBusinessLogic();
bl.ProcessCompleted += bl_ProcessCompleted; // register with
an event
bl.StartProcess();
}

// event handler
public static void bl_ProcessCompleted(object sender, bool
IsSuccessful)
{
Console.WriteLine("Process " + (IsSuccessful? "Completed
Successfully": "failed"));
}
}

public class ProcessBusinessLogic


{
// declaring an event using built-in EventHandler
public event EventHandler<bool> ProcessCompleted;

public void StartProcess()


{
try
{
Console.WriteLine("Process Started!");

// some code here..

OnProcessCompleted(true);
}
catch(Exception ex)
{
OnProcessCompleted(false);
}
}

protected virtual void OnProcessCompleted(bool IsSuccessful)


{
ProcessCompleted?.Invoke(this, IsSuccessful);
}
}
Try it
In the above example, we are passing a single boolean value to the
handlers that indicate whether the process completed successfully or
not.

If you want to pass more than one value as event data, then create a
class deriving from the EventArgs base class, as shown below.

Example: Custom EventArgs Class

class ProcessEventArgs : EventArgs


{
public bool IsSuccessful { get; set; }
public DateTime CompletionTime { get; set; }
}

The following example shows how to pass


custom ProcessEventArgs class to the handlers.

Example: Passing Custom EventArgs

class Program
{
public static void Main()
{
ProcessBusinessLogic bl = new ProcessBusinessLogic();
bl.ProcessCompleted += bl_ProcessCompleted; // register with
an event
bl.StartProcess();
}

// event handler
public static void bl_ProcessCompleted(object sender,
ProcessEventArgs e)
{
Console.WriteLine("Process " + (e.IsSuccessful? "Completed
Successfully": "failed"));
Console.WriteLine("Completion Time: " +
e.CompletionTime.ToLongDateString());
}
}

public class ProcessBusinessLogic


{
// declaring an event using built-in EventHandler
public event EventHandler<ProcessEventArgs> ProcessCompleted;
public void StartProcess()
{
var data = new ProcessEventArgs();

try
{
Console.WriteLine("Process Started!");

// some code here..

data.IsSuccessful = true;
data.CompletionTime = DateTime.Now;
OnProcessCompleted(data);
}
catch(Exception ex)
{
data.IsSuccessful = false;
data.CompletionTime = DateTime.Now;
OnProcessCompleted(data);
}
}

protected virtual void OnProcessCompleted(ProcessEventArgs e)


{
ProcessCompleted?.Invoke(this, e);
}
}
Try it

Thus, you can create, raise, register, and handle events in C#.

Learn What is the difference between delegate and event in C#?.

 Points to Remember :

1. An event is a wrapper around a delegate. It depends on the delegate.


2. Use "event" keyword with delegate type variable to declare an event.
3. Use built-in delegate EventHandler or EventHandler<TEventArgs> for
common events.
4. The publisher class raises an event, and the subscriber class registers for an
event and provides the event-handler method.
5. Name the method which raises an event prefixed with "On" with the event
name.
6. The signature of the handler method must match the delegate signature.
7. Register with an event using the += operator. Unsubscribe it using the -=
operator. Cannot use the = operator.
8. Pass event data using EventHandler<TEventArgs>.
9. Derive EventArgs base class to create custom event data class.
10. Events can be declared static, virtual, sealed, and abstract.
11. An Interface can include the event as a member.
12. Event handlers are invoked synchronously if there are multiple subscribers.

Covariance and Contravariance in C#


Covariance and contravariance allow us to be flexible when dealing
with class hierarchy.

Consider the following class hierarchy before we learn about


covariance and contravariance:

Example: Class Hierarchy

public class Small


{

}
public class Big: Small
{

}
public class Bigger : Big
{

As per the above example classes, small is a base class for big and
big is a base class for bigger. The point to remember here is that a
derived class will always have something more than a base class, so
the base class is relatively smaller than the derived class.

Now, consider the following initialization:


Class initialization

As you can see above, a base class can hold a derived class but a
derived class cannot hold a base class. In other word, an instance
can accept big even if it demands small, but it cannot accept small if
it demands big.

Now, let's learn about covariance and contravariance.

Covariance in C#
Covariance enables you to pass a derived type where a base type is
expected. Co-variance is like variance of the same kind. The base
class and other derived classes are considered to be the same kind of
class that adds extra functionalities to the base type. So covariance
allows you to use a derived class where a base class is expected
(rule: can accept big if small is expected).

Covariance can be applied on delegate, generic, array, interface, etc.

Covariance with Delegate


Covariance in delegates allows flexiblity in the return type of
delegate methods.

Example: Covariance with Delegate

public delegate Small covarDel(Big mc);

public class Program


{
public static Big Method1(Big bg)
{
Console.WriteLine("Method1");

return new Big();


}
public static Small Method2(Big bg)
{
Console.WriteLine("Method2");

return new Small();


}

public static void Main(string[] args)


{
covarDel del = Method1;

Small sm1 = del(new Big());

del= Method2;
Small sm2 = del(new Big());
}
}
Try it

Output:

Method1

Method2

As you can see in the above example, delegate expects a return type
of small (base class) but we can still assign Method1 that returns Big
(derived class) and also Method2 that has same signature as
delegate expects.

Thus, covariance allows you to assign a method to the delegate that


has a less derived return type.
ADVERTISEMENT
C# Contravariance
Contravariane is applied to parameters. Cotravariance allows a
method with the parameter of a base class to be assigned to a
delegate that expects the parameter of a derived class.

Continuing with the example above, add Method3 that has a different
parameter type than delegate:

Example: Contravariance with Delegte

delegate Small covarDel(Big mc);

class Program
{
static Big Method1(Big bg)
{
Console.WriteLine("Method1");
return new Big();
}
static Small Method2(Big bg)
{
Console.WriteLine("Method2");
return new Small();
}

static Small Method3(Small sml)


{
Console.WriteLine("Method3");

return new Small();


}
static void Main(string[] args)
{
covarDel del = Method1;
del += Method2;
del += Method3;

Small sm = del(new Big());


}
Output:
Method1

Method2

Method3

As you can see, Method3 has a parameter of Small class whereas


delegate expects a parameter of Big class. Still, you can use Method3
with the delegate.

You can also use covariance and contravariance in the same method
as shown below.

Example: Covariance and Contravariance

delegate Small covarDel(Big mc);

class Program
{

static Big Method4(Small sml)


{
Console.WriteLine("Method3");

return new Big();


}

static void Main(string[] args)


{
covarDel del = Method4;

Small sm = del(new Big());


}
}
Output:

Method4
C# - Extension Method
Extension methods, as the name suggests, are additional methods.
Extension methods allow you to inject additional methods without
modifying, deriving or recompiling the original class, struct or
interface. Extension methods can be added to your own custom
class, .NET framework classes, or third party classes or interfaces.

In the following example, IsGreaterThan() is an extension method


for int type, which returns true if the value of the int variable is
greater than the supplied integer parameter.

Example: Extension Method


int i = 10;

bool result = i.IsGreaterThan(100); //returns false

The IsGreaterThan() method is not a method of int data type (Int32


struct). It is an extension method written by the programmer for the
int data type. The IsGreaterThan() extension method will be available
throughout the application by including the namespace in which it
has been defined.

The extension methods have a special symbol in intellisense of the


visual studio, so that you can easily differentiate between class
methods and extension methods.

Extension Method Symbol in


visual studio intellisense

Now let's see how to write an extension method.


LINQ is built upon extension methods that operate on IEnumerable and
IQeryable type.

An extension method is actually a special kind of static method


defined in a static class. To define an extension method, first of all,
define a static class.

For example, we have created an IntExtensions class under


the ExtensionMethods namespace in the following example. The
IntExtensions class will contain all the extension methods applicable
to int data type. (You may use any name for namespace and class.)

Example: Create a Class for Extension Methods


namespace ExtensionMethods
{
public static class IntExtensions
{

}
}

Now, define a static method as an extension method where the first


parameter of the extension method specifies the type on which the
extension method is applicable. We are going to use this extension
method on int type. So the first parameter must be int preceded with
the this modifier.

For example, the IsGreaterThan() method operates on int, so the


first parameter would be, this int i.

Example: Define an Extension Method


namespace ExtensionMethods
{
public static class IntExtensions
{
public static bool IsGreaterThan(this int i, int value)
{
return i > value;
}
}
}
Now, you can include the ExtensionMethods namespace wherever
you want to use this extension method.

Example: Extension method


using ExtensionMethods;

class Program
{
static void Main(string[] args)
{
int i = 10;

bool result = i.IsGreaterThan(100);

Console.WriteLine(result);
}
}
Try it
Output:

false

 Note:
The only difference between a regular static method and an extension
method is that the first parameter of the extension method specifies the
type that it is going to operator on, preceded by the this keyword.
 Points to Remember :

1. Extension methods are additional custom methods which were


originally not included with the class.
2. Extension methods can be added to custom, .NET Framework or third
party classes, structs or interfaces.
3. The first parameter of the extension method must be of the type for
which the extension method is applicable, preceded by the this keyword.
4. Extension methods can be used anywhere in the application by
including the namespace of the extension method.

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.

MemoryStream: MemoryStream reads or writes bytes that are


stored in memory.

BufferedStream: BufferedStream reads or writes bytes from other


Streams to improve certain I/O operations' performance.

NetworkStream: NetworkStream reads or writes bytes from a


network socket.

PipeStream: PipeStream reads or writes bytes from different


processes.

CryptoStream: CryptoStream is for linking data streams to


cryptographic transformations.

The following diagram shows the hierarchy of stream classes:


Str
eam Classes Hierarchy

Stream Readers and Writers


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.

StreamWriter: StreamWriter is a helper class for writing a string to


a Stream by converting characters into bytes. It can be used to write
strings to different Streams such as FileStream, MemoryStream, etc.

BinaryReader: BinaryReader is a helper class for reading primitive


datatype from bytes.

BinaryWriter: BinaryWriter writes primitive types in binary.

Str
eam IO
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.

Working with Files & Directories in C#


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.

Class Name Usage

File File is a static class that provides different functionalities like copy, create, move, delete, open for reading or
/writing, encrypt or decrypt, check if a file exists, append lines or text to a file�s content, get last access time,
etc.

FileInfo The FileInfo class provides the same functionality as a static File class. You have more control on how you do
read/write operations on a file by writing code manually for reading or writing bytes from a file.

Directory Directory is a static class that provides functionality for creating, moving, deleting and accessing subdirectories.

DirectoryInfo DirectoryInfo provides instance methods for creating, moving, deleting and accessing subdirectories.

Path Path is a static class that provides functionality such as retrieving the extension of a file, changing the extension
Class Name Usage

of a file, retrieving the absolute physical path, and other path related functionalities.

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.

Important Methods of Static File Class


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.

GetAccessContro Gets a FileSecurity object that encapsulates the access control list (ACL) entries for a specified file.
l
Method Usage

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.

Append Text Lines


Use AppendAllLines() method to append multiple text lines to the
specified file as shown below.

Example: Append all text lines to a file

string dummyLines = "This is first line." + Environment.NewLine +


"This is second line." + Environment.NewLine +
"This is third line.";

//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.

Example: Overwrite existing texts

//Opens DummyFile.txt and write texts. If file is not exists then


create and open.
File.WriteAllText(@"C:\DummyFile.txt", "This is dummy text");

The following example shows how to perform different operations


using static File class.

Example: Multiple File operations

//Check whether file is exists or not at particular location


bool isFileExists = File.Exists(@"C:\ DummyFile.txt"); // returns
false

//Copy DummyFile.txt as new file DummyFileNew.txt


File.Copy(@"C:\DummyFile.txt", @"D:\NewDummyFile.txt");

//Get when the file was accessed last time


DateTime lastAccessTime = File.GetLastAccessTime(@"C:\DummyFile.txt");

//get when the file was written last time


DateTime lastWriteTime = File.GetLastWriteTime(@"C:\DummyFile.txt");

// Move file to new location


File.Move(@"C:\DummyFile.txt", @"D:\DummyFile.txt");

//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.

Visit MSDN to know all the methods of the static File class.

 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.

Important Properties and Methods of FileInfo:


Property Usage

Directory Gets an instance of the parent directory.

DirectoryName Gets a string representing the directory's full path.

Exists Gets a value indicating whether a file exists.

Extension Gets the string representing the extension part of the file.

FullName Gets the full path of the directory or file.


Property Usage

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

Length Gets the size, in bytes, of the current file.

Name Gets the name of the file.

Method Usage

AppendText Creates a StreamWriter that appends text to the file represented by this instance of the FileInfo.

CopyTo Copies an existing file to a new file, disallowing the overwriting of an existing file.

Create Creates a file.

CreateText Creates a StreamWriter that writes a new text file.

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.

GetAccessContro Gets a FileSecurity object that encapsulates the access control list (ACL) entries for a specified file.
l

MoveTo Moves a specified file to a new location, providing the option to specify a new file name.

Open Opens a in the specified FileMode.

OpenRead Creates a read-only FileStream.

OpenText Creates a StreamReader with UTF8 encoding that reads from an existing text file.

OpenWrite Creates a write-only FileStream.

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.

ToString Returns a path as string.


The following example shows how to read bytes from a file manually
and then convert them to a string using UTF8 encoding:

Example: Read file using FileInfo class

//Create object of FileInfo for specified path


FileInfo fi = new FileInfo(@"D:\DummyFile.txt");

//Open file for Read\Write


FileStream fs = fi.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite,
FileShare.ReadWrite);

//create byte array of same size as FileStream length


byte[] fileBytes = new byte[fs.Length];

//define counter to check how much bytes to read. Decrease the counter
as you read each byte
int numBytesToRead = (int)fileBytes.Length;

//Counter to indicate number of bytes already read


int numBytesRead = 0;

//iterate till all the bytes read from FileStream


while (numBytesToRead > 0)
{
int n = fs.Read(fileBytes, numBytesRead, numBytesToRead);

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");

//Open file for Read\Write


FileStream fs = fi.Open(FileMode.OpenOrCreate, FileAccess.Read ,
FileShare.Read);

//Create object of StreamReader by passing FileStream object on which


it needs to operates on
StreamReader sr = new StreamReader(fs);

//Use ReadToEnd method to read all the content from file


string fileContent = sr.ReadToEnd();

//Close StreamReader object after operation


sr.Close();
fs.Close();

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:

Example: Write texts to file using StreamWriter

//Create object of FileInfo for specified path


FileInfo fi = new FileInfo(@"D:\DummyFile.txt");

//Open file for Read\Write


FileStream fs = fi.Open(FileMode.OpenOrCreate, FileAccess.Write,
FileShare.Read );

//Create StreamWriter object to write string to FileSream


StreamWriter sw = new StreamWriter(fs);
sw.WriteLine("Another line from streamwriter");
sw.Close();
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:

Example: StreamReader & StreamWriter

//Create FileInfo object for DummyFile.txt


FileInfo fi = new FileInfo(@"D:\DummyFile.txt");

//open DummyFile.txt for read operation


FileStream fsToRead = fi.Open(FileMode.OpenOrCreate,
FileAccess.ReadWrite , FileShare.ReadWrite);

//open DummyFile.txt for write operation


FileStream fsToWrite = fi.Open(FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.ReadWrite);

//get the StreamReader

StreamReader sr = new StreamReader(fsToRead);


//read all texts using StreamReader object
string fileContent = sr.ReadToEnd();
sr.Close();

//get the StreamWriter


StreamWriter sw = new StreamWriter(fsToWrite);
//write some text using StreamWriter
sw.WriteLine("Another line from streamwriter");
sw.Close();

//close all Stream objects


fsToRead.Close();
fsToWrite.Close();

Thus you can use FileInfo, StreamReader and StreamWriter class to


read/write contents from physical file.

C# - Object Initializer Syntax


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.
Example: Object Initializer Syntax

public class Student


{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
public string Address { get; set; }
}

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.

Example: Object Initializer Syntax at Compile time

Student __student = new Student();


__student.StudentID = 1;
__student.StudentName = "Bill";
__student.Age = 20;
__student.StandardID = 10;
__student.Address = "Test";

Student std = __student;


Collection Initializer Syntax
Collection can be initialized the same way as class objects using
collection initializer syntax.

Example: Object initializer Syntax

var student1 = new Student() { StudentID = 1, StudentName = "John" };


var student2 = new Student() { StudentID = 2, StudentName = "Steve" };
var student3 = new Student() { StudentID = 3, StudentName = "Bill" } ;
var student4 = new Student() { StudentID = 3, StudentName = "Bill" };
var student5 = new Student() { StudentID = 5, StudentName = "Ron" };

IList<Student> studentList = new List<Student>() {


student1,
student2,
student3,
student4,
student5
};
Try it

You can also initialize collections and objects at the same time.

Example: Collection initializer Syntax

IList<Student> studentList = new List<Student>() {


new Student() { StudentID = 1, StudentName =
"John"} ,
new Student() { StudentID = 2, StudentName =
"Steve"} ,
new Student() { StudentID = 3, StudentName =
"Bill"} ,
new Student() { StudentID = 3, StudentName =
"Bill"} ,
new Student() { StudentID = 4, StudentName = "Ram"
} ,
new Student() { StudentID = 5, StudentName = "Ron"
}
};
Try it

You can also specify null as an element:


Example: Collection initializer Syntax

IList<Student> studentList = new List<Student>() {


new Student() { StudentID = 1,
StudentName = "John"} ,
null
};

Advantages of Initializers
 Initializer syntax makes a code more readable, easy to add elements into the
collection.
 Useful in multi-threading.

You might also like