0% found this document useful (0 votes)
17 views25 pages

c#

This document covers key concepts in C# including exception handling, delegates, events, and multithreading. It explains how to manage exceptions using try-catch-finally blocks, the use of delegates to reference methods, and the implementation of events for handling actions in a program. Additionally, it discusses multithreading functionalities and synchronization in C#.

Uploaded by

sunitha
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views25 pages

c#

This document covers key concepts in C# including exception handling, delegates, events, and multithreading. It explains how to manage exceptions using try-catch-finally blocks, the use of delegates to reference methods, and the implementation of events for handling actions in a program. Additionally, it discusses multithreading functionalities and synchronization in C#.

Uploaded by

sunitha
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 25

UNIT 4

EXCEPTION HANDLING, DELEGATES & EVENTS,


MULTITHREADING

Exceptions in C# and .Net


Handling Exceptions using the try-catch-finally blocks
Delegates Basics
Delegates in the .Net Framework
Passing delegates to methods
Multicast Delegates
Events and Events handling in C#
Multicast events
Multithreading in C#
Thread Functionality
System.Threading.Thread class
using join() method
Thread Synchronization.

Exceptions in C# and .Net

 An exception is a problem that arises during the execution of a program.


 Exception Handling in C# is a process to handle runtime errors. We perform
exception handling so that normal flow of the application can be maintained even after
runtime errors
 All exceptions in .Net are objects.
 The System.Exception class is the base class for all exceptions in .Net.
 Any method can raise or throw an exception in the case of some unexpected event
during its execution using the throw keyword in C#. The thrown exception can be
caught or dealt within the calling method using the try...catch block
 When an exception is raised during the execution of the code inside the try block,
the remaining code in the try block is neglected and the control of execution is
transferred to the respective catch or finally block.
 If you do not catch an exception, the runtime environment (Common Language
Runtime or CLR) will catch it on your behalf, causing your program to terminate.

Handling Exceptions using the try...catch...finally blocks

Use of the try...catch block

C# try/catch

In C# programming, exception handling is performed by try/catch statement.


The try block in C# is used to place the code that may throw exception.
The catch block is used to handled the exception. The catch block must be preceded by try block.
The try and catch keywords come in pairs
Syntax
try
{
// Block of code to try
}
catch (Exception e)
{
// Block of code to handle errors
}

Example:
using System;
public class ExExample
{
public static void Main(string[] args)
{
try
{
int a = 10;
int b = 0;
int x = a / b;
}
catch (Exception e)
{
Console.WriteLine(e);
}

Console.WriteLine("Rest of the code");


}
}

Output:
System.DivideByZeroException: Attempted to divide by zero.
Rest of the code

C# finally

C# finally block is used to execute important code which is to be executed whether exception is
handled or not. It must be preceded by catch or try block.
Example:
try
{
int[] myNumbers = {1, 2, 3};
Console.WriteLine(myNumbers[10]);
}
catch (Exception e)
{
Console.WriteLine("Something went wrong.");
}
finally
{
Console.WriteLine("The 'try catch' is finished.");
}
Rest of the code

The output will be:


Something went wrong.
The 'try catch' is finished.

The throw keyword

A method can throw an exception using the throw keyword


The throw statement allows you to create a custom error.
The throw statement is used together with an exception class. There are many exception
classes available in
C#: ArithmeticException, FileNotFoundException, IndexOutOfRangeException, TimeOutE
xception, etc:

Example:
static void checkAge(int age)
{
if (age < 18)
{
throw new ArithmeticException("Access denied - You must be at least 18 years old.");
}
else
{
Console.WriteLine("Access granted - You are old enough!");
}
}

static void Main(string[] args)


{
checkAge(15);
}
The error message displayed in the program will be:
System.ArithmeticException: 'Access denied - You must be at least 18 years old.'

Catching Multiple Exceptions using multiple catch blocks

In C#, You can use more than one catch block with the try block. Generally, multiple catch
block is used to handle different types of exceptions means each catch block is used to
handle different type of exception.
It is possible to catch multiple (different) exceptions that may be thrown in a try block using
multiple (or a series of) catch blocks.
C# does not allow you to use multiple catch block for the same type of exception

In general, the catch block is checked within the order in which they have occurred in the
program. If the given type of exception is matched with the first catch block, then first catch
block executes and the remaining of the catch blocks are ignored. And if the starting catch
block is not suitable for the exception type, then compiler search for the next catch block.

Syntax:
try {

// Your code

// 1st catch block


catch(Exception_Name) {

// Code

// 2nd catch block


catch(Exception_Name) {

// Code

.
.
.
.

Example:
// C# program to illustrate the
// use of multiple catch block
using System;

class GFG {

// Main Method
static void Main()
{

// Here, number is greater than divisor


int[] number = { 8, 17, 24, 5, 25 };
int[] divisor = { 2, 0, 0, 5 };

// --------- try block ---------

for (int j = 0; j < number.Length; j++)

// Here this block raises two different


// types of exception, i.e. DivideByZeroException
// and IndexOutOfRangeException
try {

Console.WriteLine("Number: " + number[j]);


Console.WriteLine("Divisor: " + divisor[j]);
Console.WriteLine("Quotient: " + number[j] / divisor[j]);
}

// Catch block 1

// This Catch block is for


// handling DivideByZeroException
catch (DivideByZeroException) {

Console.WriteLine("Not possible to Divide by zero");


}

// Catch block 2

// This Catch block is for


// handling IndexOutOfRangeException
catch (IndexOutOfRangeException) {
Console.WriteLine("Index is Out of Range");
}
}
}

Output:
Number: 8
Divisor: 2
Quotient: 4
Number: 17
Divisor: 0
Not possible to Divide by zero
Number: 24
Divisor: 0
Not possible to Divide by zero
Number: 5
Divisor: 5
Quotient: 1
Number: 25
Index is Out of Range

Defining your own custom exceptions(User defines Exceptions)


C# allows us to create user-defined or custom exception.
It is used to make the meaningful exception.
To do this, we need to inherit Exception class.
User-defined exception classes are derived from the Exception class.
using System;

Example:
public class InvalidAgeException : Exception
{
public InvalidAgeException(String message)
: base(message)
{

}
}
public class TestUserDefinedException
{
static void validate(int age)
{
if (age < 18)
{
throw new InvalidAgeException("Sorry, Age must be greater than 18");
}
}
public static void Main(string[] args)
{
try
{
validate(12);
}
catch (InvalidAgeException e) { Console.WriteLine(e); }
Console.WriteLine("Rest of the code");
}
}
Output:
InvalidAgeException: Sorry, Age must be greater than 18
Rest of the code

C# Checked and Unchecked

C# provides checked and unchecked keyword to handle integral type exceptions.


Checked and unchecked keywords specify checked context and unchecked context
respectively.
In checked context, arithmetic overflow raises an exception whereas
In an unchecked context, arithmetic overflow is ignored and result is truncated.

C# Checked
The checked keyword is used to explicitly check overflow and conversion of integral type
values at compile time.
C# Checked Example
This program throws an exception and stops program execution.
using System;
namespace CSharpProgram
{
class Program
{
static void Main(string[] args)
{
checked
{
int val = int.MaxValue;
Console.WriteLine(val + 2);
}
}
}
}
Output:
Unhandled Exception: System.OverflowException: Arithmetic operation resulted in an o

C# Unchecked
The Unchecked keyword ignores the integral type arithmetic exceptions. It does not check
explicitly and produce result that may be truncated or wrong.

Example
using System;
namespace CSharpProgram
{
class Program
{
static void Main(string[] args)
{
unchecked
{
int val = int.MaxValue;
Console.WriteLine(val + 2);
}
}
}
}
Output:
-2147483647
Delegates Basics

In C#, we can also pass a method as a parameter to a different method using a delegate. We
use the delegate keyword to define a delegate.

A delegate is an object which refers to a method or you can say it is a reference type variable
that can hold a reference to the methods.

Types of Delegates
1. Single cast
2. Multicast

Declaration of Delegates

Delegate type can be declared using the delegate keyword. Once a delegate is declared,
delegate instance will refer and call those methods whose return type and parameter-list
matches with the delegate declaration.

Syntax:
[modifier] delegate [return_type] [delegate_name] ([parameter_list]);

Here, Name is the name of the delegate and it is taking parameter. Suppose we have a
delegate having int as the parameter.

Example : public delegate void Name(int x)


In this case, our delegate will take a method (name of a method) which will also have
an int as its parameter and void return type. It means the method passed to a delegate must
have the same parameters and return type.
using System;
class Test
{
public delegate int NewDelegate(int x, int y);

static int Add(int x, int y)


{
return x+y;
}
}

Here, NewDelegate is a delegate which has two integers parameter x and y. It means that it
will take a method which also has two integers as its parameter and also integer return type.
So, it can take the method Add.

To create a new delegate, we either use the new keyword or simply decalare as we declare
variables.
using System;
class Test
{
public delegate int NewDelegate(int x, int y);

static int Add(int x, int y)


{
return x+y;
}

static int Subtract(int x, int y)


{
return x-y;
}

static void Main(string[] args)


{
NewDelegate d1 = Add; //creating delegate
NewDelegate d2 = Subtract; //creating delegate

NewDelegate d3 = new NewDelegate(Add); //creating delegate using new keyword


NewDelegate d4 = new NewDelegate(Subtract); //creating delegate new keyword

Console.WriteLine(d1(10, 20));
Console.WriteLine(d2(10, 20));
}
}
Delegates are similar to object references, but are used to reference methods instead of
objects. The type of a delegate is the type or signature of the method rather than the class.
Hence a delegate has three properties:

 The type or signature of the method that the delegate can point to
 The delegate reference which can be used to reference a method
 The actual method referenced by the delegate

The type or signature of the method the delegate can point to


Before using a delegate, we need to specify the type or signature of the method the
delegate can reference. The signature of a method includes its return type and the type of
parameters which it requires to be passed.
Example
The signature will be:
int aMethod(int p, int q)
the signature only involves its return type and parameters.
delegate int MyDelegate(int p, int q);
Here we have defined a delegate type with the name 'MyDelegate'. The reference of this
delegate type can be used to point to any method which takes two integers as parameters
and returns an integer value.

The delegate reference, that can be used to reference a method


Once we have defined a delegate type, we can set it to reference actual methods with
matching signatures. A delegate reference can be declared just like an object reference.
For example, a reference of type MyDelegate (defined above) can be declared as:
MyDelegate arithMethod;
The delegate reference arithMethod can now reference any method whose signature is
identical to the signature of MyDelegate.
The actual method referenced by the delegate
The delegate reference can be made to reference any method with a matching signature by
passing its name as the parameter of delegate:
arithMethod = new MyDelegate(Add);
Here, the arithMethod delegate reference is made to point to the Add() method by passing
its name as a parameter to the delegate type (MyDelegate). The last two steps can be
merged together in a single statement, like this:-
MyDelegate arithMethod = new MyDelegate(Add);

Calling the actual method through its delegate


Once the delegate reference 'arithMethod' has been made to point to the Add() method, it can
be used to call the actual method like this:-
int r = arithMethod(3, 4);
complete program
namespace CSharpSchool
{
class Test
{
delegate int MyDelegate(int p, int q);
static void Main()
{
MyDelegate arithMethod = new MyDelegate(Add);
int r = arithMethod(3, 4);
Console.WriteLine("The result of arithmetic operation `+' on 3 and 4 is:
{0}", r);
}
static int Add(int a, int b)
{
return a + b;
}
}
}

The result of the above program will be


The result of arithmetic operation `+' on 3 and 4 is: 7

Delegates in the .Net Framework


In .Net delegates are present as a reference type, and all delegates inherit from the
System.Delegate type.

A delegate is a reference type derived from System.Delegate and its instances can be
used to call methods with matching signatures
A delegate is like a special kind of pointer in programming that can refer to a method
(function). You can use this delegate to call that method. So, it's a way to indirectly
refer to and execute methods with similar signatures (input and output types).
Delegate, the delegates can not be defined within a method (which is also true for
ordinary types). This is the reason why we have defined the delegate MyDelegate outside
the Main() method in the example code of this lesson.
class Test
{
delegate int MyDelegate(int p, int
q);static void Main()
{
MyDelegate arithMethod = null;
...
}
}

Passing delegates to methods

We can also pass a delegate to a method.


Just like a reference to an object can be passed to other objects, the delegate reference
of one method can be passed to another method.
using System;
class Test
{
public delegate int NewDelegate(int x, int y);

static void Display(NewDelegate d)


{
Console.WriteLine(d(10, 20));
}

static int Add(int x, int y)


{
return x+y;
}

static void Main(string[] args)


{
NewDelegate d1 = new NewDelegate(Add);
Display(d1);
}
}
Output: 30
In this example, the Display method is taking a delegate NewDelegate as its parameter
and then invoking it in Console.WriteLine(d(10, 20));.

C# Multicast Delegate

In C#, a delegate can also point to multiple methods and is known as multicast delegate. We
use + and - operators to add and subtract methods from a delegate.
So, if d is a delegate, then we can add a method M to it using d = d+M or d += M. In this
case, invoking d will invoke all the methods in d sequentially.
Similarly, we can use - to remove methods from a delegate.
multicast delegates are sub-types of System.MulticastDelegate, which itself is a subclass of
System.Delegate.
The most important point to remember about multicast delegates is that "The return type of a
multicast delegate type must be void".

using System;
class Test
{
public delegate void NewDelegate();

static void Display1()


{
Console.WriteLine("Hello");
}

static void Display2()


{
Console.WriteLine("CodesDope");
}

static void Main(string[] args)


{
NewDelegate d = Display1;
d = d+Display2;

d();

d = d-Display2;

d();
}
}
Events and Event Handling

Events are certain actions that happen during the execution of a program that the application
wishes to be notified about, so it can respond. An event can be a mouse click, a keystroke or
the coming of a certain time (alarm).
An event is basically a message which is said to be fired or triggered when the respective
action occurs.
A class that raises an event is called an 'event sender', a class that receives an event is called
and 'event consumer' and a method which is used to handle a particular event is called an
'event handler'.

Event Handling in C#
In .Net, events are implemented as multicast delegates.
In C# events are a first class (basic) language construct, and are defined using the event
keyword.
The steps for implementing events and event handling are:
1. Define a public delegate for the event outside any class boundary. The
conventional signature of a delegate for an event is:
public void EventDelegate(object sender, EventArgs e)
2. Define a class to generate or raise the event. Define a public event in the class
using the event keyword and the public delegate:
public event EventDelegate MyEvent
Write some logic to raise the event. When raising an event, the first argument is
usually the sender or originator of the event. The second argument is a sub-type of
System.EventArgs, which holds any additional data to be passed to the event
handler.
class SomeEventArgs : EventArgs
{
...
}
An event is generally raised like this:
SomeEventArgs someData = new SomeEventArgs(/*some necessary arguments*/);
MyEvent(this, someData);
Or if no data needs to be sent, the event is raised like this:
MyEvent(this, null);
3. Define a class to receive the events. This class is usually the main application class
containing the Main() method Write an event handler method in the class. The
signature of the event handler must be identical to that of the public delegate created
in step 1. The name of the event handler method conventionally starts with the word
"On", e.g.
public void OnMyEvent(object sender, EventArgs e)
{
// handle the event
}
Instantiate the event generator class created in step 2 like this:
EventClass eventObj = new EventClass();
Add the event handler written in the current class to the event generator class' event.
eventObj.MyEvent += new EventDelegate(OnMyEvent);
Now the event handler 'OnMyEvent()' will be called automatically whenever the event
'MyEvent' is triggered.

Multicast events

Since events are implemented as multicast delegates in C#, we can subscribe multiple
event handlers to a single event.
class Test
{
static void Main()
{
ClockTimer clockTimer = new
ClockTimer(); clockTimer.Timer += new
TimerEvent(OnClockTick);
clockTimer.Timer += new
TimerEvent(OnClockTick2);
clockTimer.Start();
}
public static void OnClockTick(object sender, EventArgs e)
{
Console.WriteLine("Received a clock tick event!");
}
public static void OnClockTick2(object sender, EventArgs e)
{
Console.WriteLine("Received a clock tick event in OnClockTick2!");
}
}
Here we have introduced another event handler, 'OnClockTick2', and have subscribed it
also to the Timer event in the Main() method using the '+=' operator.

The output of this program is:


Received a clock tick event!
Received a clock tick event in OnClockTick2!Received
a clock tick event!
Received a clock tick event in OnClockTick2!Received
a clock tick event!
Received a clock tick event in OnClockTick2!Received
a clock tick event!
Received a clock tick event in OnClockTick2!Received
a clock tick event!
Received a clock tick event in OnClockTick2!
Press any key to continue
As can be seen in the output above, now both the OnClockTick() and OnClockTick2() are
invoked each time the event is raised.

Process: program or application that is currently running on a computer system.


Thread: a thread is a single sequence of instructions that a process can execute.
A process represents an application whereas a thread represents a module of the application.
Process is heavyweight component whereas thread is lightweight. A thread can be termed as
lightweight subprocess because it is executed inside a process.
In C#, the System.Threading namespace offers classes that allow you to manipulate
threads.
Multithreading
Multithreading is a feature provided by the operating system that enables your application
to have more than one execution path at the same time.

Multithreading in C#

Multithreading in C# is a process in which multiple threads work simultaneously.


It is a process to achieve multitasking.
It saves time because multiple tasks are being executed at a time. To create multithreaded
application in C#, we need to use System.Threding namespace.
A thread in .Net is represented by the System.Threading.Thread class.
We can create multiple threads in our program by creating multiple instances (objects) of
this class.
A thread starts its execution by calling the specified method and terminates when the
execution of that method gets completed.
We can specify the method name that the thread will call when it starts by passing a delegate
of the ThreadStart type in the Thread class constructor. The delegate
System.Threading.ThreadStart may reference any method with has the void return type and
which takes no arguments.
void Function1() { // Some work here }
void Function2() { // Some other work here }
Thread thread1 = new Thread(new ThreadStart(Function1));
Thread thread2 = new Thread(new ThreadStart(Function2));
thread1.Start();
thread2.Start();

In the example above, Function1 and Function2 will run concurrently, each in its thread.
The order of execution is not determined by the order in which the threads are started. It’s
managed by the thread scheduler, which is part of the .NET runtime.

Thread Functionality

C# Thread class provides properties and methods to create and control threads. It is found in
System.Threading namespace.

Static members of the System.Threading.Thread class


The static property CurrentThread gives a reference to the currently executing thread.
Another important static member of the Thread class is the Sleep() method. It causes the
currently executing thread to pause temporarily for the specified amount of time.

Instance members of the System.Threaing.Thread class


1.Priority()
2.Name()
3.IsAlive
4.Threadstate()
5.start()
6.Abort()
7.Suspend()
8.Resume()
9.Join()

C# Thread Properties
A list of important properties of Thread class are given below:

Property Description

CurrentThread returns the instance of currently running


thread.

IsAlive checks whether the current thread is alive or


not. It is used to find the execution status of
the thread.

IsBackground is used to get or set value whether current


thread is in background or not.
ManagedThreadId is used to get unique id for the current
managed thread.

Name is used to get or set the name of the current


thread.

Priority is used to get or set the priority of the


current thread.

ThreadState is used to return a value representing the


thread state.

C# Thread Methods
A list of important methods of Thread class are given below:

Method Description

Abort() is used to terminate the thread. It raises


ThreadAbortException.

Interrupt() is used to interrupt a thread which is


in WaitSleepJoin state.

Join() is used to block all the calling threads until this


thread terminates.

ResetAbort() is used to cancel the Abort request for the current


thread.

Resume() is used to resume the suspended thread. It is


obselete.

Sleep(Int32) is used to suspend the current thread for the


specified milliseconds.

Start() changes the current state of the thread to


Runnable.

Suspend() suspends the current thread if it is not suspended.


It is obselete.

Yield() is used to yield the execution of current thread to


another thread.
C# Threading Example: static method

We can call static and non-static methods on the execution of the thread. To call the static
and non-static methods, you need to pass method name in the constructor of ThreadStart
class. For static method, we don't need to create the instance of the class. You can refer it by
the name of class.
using System;
using System.Threading;
public class MyThread
{
public static void Thread1()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
}
}
public class ThreadExample
{
public static void Main()
{
Thread t1 = new Thread(new ThreadStart(MyThread.Thread1));
Thread t2 = new Thread(new ThreadStart(MyThread.Thread1));
t1.Start();
t2.Start();
}
}
Output:
The output of the above program can be anything because there is context switching between
the threads.
0
1
2
3
4
5
0
1
2
3
4
5
6
7
8
9
6
7
8
9

C# Threading Example: non-static method


For non-static method, you need to create instance of the class so that you can refer it in the
constructor of ThreadStart class.
Backward Skip 10sPlay VideoForward Skip 10s
ADVERTISEMENT
using System;
using System.Threading;
public class MyThread
{
public void Thread1()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
}
}
public class ThreadExample
{
public static void Main()
{
MyThread mt = new MyThread();
Thread t1 = new Thread(new ThreadStart(mt.Thread1));
Thread t2 = new Thread(new ThreadStart(mt.Thread1));
t1.Start();
t2.Start();
}
}
Output:
Like above program output, the output of this program can be anything because there is
context switching between the threads.
0
1
2
3
4
5
0
1
2
3
4
5
6
7
8
9
6
7
8
9

C# Threading Example: performing different tasks on each thread

Let's see an example where we are executing different methods on each thread.
using System;
using System.Threading;

public class MyThread


{
public static void Thread1()
{
Console.WriteLine("task one");
}
public static void Thread2()
{
Console.WriteLine("task two");
}
}
public class ThreadExample
{
public static void Main()
{
Thread t1 = new Thread(new ThreadStart(MyThread.Thread1));
Thread t2 = new Thread(new ThreadStart(MyThread.Thread2));
t1.Start();
t2.Start();
}
}
Output:
task one
task two
Using Join() to wait for running threads

In C#, you can create and run multiple threads simultaneously to perform different tasks
concurrently. Sometimes, it is necessary to wait for one thread to complete before starting
another thread or wait for all threads to complete before proceeding further. To achieve
this, you can use the following methods to join threads in C#:

Thread.Join(): The Join method of the Thread class waits for the thread to complete its
execution before continuing with the execution of the calling thread. This method blocks the
calling thread until the target thread has completed its execution.
Example:
C#

using System;
using System.Threading;

class Program
{
static void Main(string[] args)
{
Thread t1 = new Thread(() =>
Console.WriteLine("Thread 1"));
Thread t2 = new Thread(() =>
Console.WriteLine("Thread 2"));

t1.Start();
t2.Start();

t1.Join();
t2.Join();

Console.WriteLine("Main Thread");
}
}

Output
Thread 1
Thread 2
Main Thread
Thread Synchronization

Synchronization is a technique that allows only one thread to access the resource for the
particular time. No other thread can interrupt until the assigned thread finishes its task.

Advantage of Thread Synchronization


Consistency Maintain
No Thread Interference

C# Lock
We can use C# lock keyword to execute program synchronously. It is used to get lock for the
current thread, execute the task and then release the lock. It ensures that other thread does not
interrupt the execution until the execution finish.

C# Thread Synchronization Example


In this example, we are using lock. This example executes synchronously. In other words,
there is no context-switching between the threads. In the output section, we can see that
second thread starts working after first threads finishes its tasks.
using System;
using System.Threading;
class Printer
{
public void PrintTable()
{
lock (this)
{
for (int i = 1; i <= 10; i++)
{
Thread.Sleep(100);
Console.WriteLine(i);
}
}
}
}
class Program
{
public static void Main(string[] args)
{
Printer p = new Printer();
Thread t1 = new Thread(new ThreadStart(p.PrintTable));
Thread t2 = new Thread(new ThreadStart(p.PrintTable));
t1.Start();
t2.Start();
}
}
Output:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10

You might also like