40
Exceptions Exceptions and and Object Lifetime Object Lifetime Chapter - 5 Chapter - 5

5.Exceptions

Embed Size (px)

DESCRIPTION

CS Notes

Citation preview

Exceptions Exceptions and and

Object LifetimeObject Lifetime

Chapter - 5Chapter - 5

Chapter ObjectivesChapter Objectives

What is an Exception? – basicsWhat is an Exception? – basics System.Exception ClassSystem.Exception Class Catching an ExceptionCatching an Exception System Level ExceptionsSystem Level Exceptions Building Customized ExceptionsBuilding Customized Exceptions Multiple ExceptionsMultiple Exceptions Garbage Collection - basicsGarbage Collection - basics What is "finally"?What is "finally"? Building Finallizable and Disposable TypesBuilding Finallizable and Disposable Types

IntroductionIntroduction An exception is any error condition or An exception is any error condition or

unexpected behavior encountered by an unexpected behavior encountered by an executing program. These are run time executing program. These are run time anomalies.anomalies.

In the .NET Framework, an exception is an In the .NET Framework, an exception is an object that inherits from the object that inherits from the System.Exception System.Exception classclass

An exception is thrown from an area of An exception is thrown from an area of code where a problem has occurredcode where a problem has occurred

.NET base class libraries define: .NET base class libraries define: OutOfMemoryException, OutOfMemoryException, IndexOutOfRangeException, IndexOutOfRangeException, FileNotFoundException, and so onFileNotFoundException, and so on

.NET Exceptions.NET Exceptions

A type that represents the details of A type that represents the details of the exceptional circumstancethe exceptional circumstance

A method that A method that throwsthrows the exception the exception to the callerto the caller

A block of code that will invoke the A block of code that will invoke the exception-ready methodexception-ready method

A block of code that will process or A block of code that will process or catchcatch the exception the exception

.NET Exceptions ….NET Exceptions …

The CLR supports an exception handling The CLR supports an exception handling model based on the concepts of exception model based on the concepts of exception objects and protected blocks of codeobjects and protected blocks of code

The runtime creates an object to represent The runtime creates an object to represent an exception when it occurs. You can also an exception when it occurs. You can also create your own exception classes by create your own exception classes by deriving classes from the appropriate base deriving classes from the appropriate base exceptionexception

Each language uses a form of Each language uses a form of try/catch/finallytry/catch/finally structured exception structured exception handlinghandling

Why Exceptions?Why Exceptions?

Code that uses exceptions are clearer and Code that uses exceptions are clearer and more robust than other methodsmore robust than other methodsbool RemoveFromAccount(string AcctID, decimal Amount)bool RemoveFromAccount(string AcctID, decimal Amount)

{{

bool Exists =bool Exists = VerifyAmount(AcctID);VerifyAmount(AcctID);if (Exists)if (Exists){ {

bool CanWithDraw = CheckAv(AcctID, Amount);bool CanWithDraw = CheckAv(AcctID, Amount);if (CanWithDraw) if (CanWithDraw) { return WithDraw(AcctID, Amount); }{ return WithDraw(AcctID, Amount); }

}}return false;return false;

}}

Disadvantages of Disadvantages of Traditional MethodsTraditional Methods

Code that depends on return value – must Code that depends on return value – must provide additional error parameters or call provide additional error parameters or call other functions (e.g. Win32 API)other functions (e.g. Win32 API)

Returning error code – must be handled Returning error code – must be handled properlyproperly

Error codes are difficult to extend and Error codes are difficult to extend and update. The entire source code must be update. The entire source code must be updated for any new error codesupdated for any new error codes

C# uses rich Exception object which C# uses rich Exception object which contains info about failure conditioncontains info about failure condition

Handling ExceptionsHandling Exceptions

To handle an exception you must protect To handle an exception you must protect with a with a trytry block and have at least one block and have at least one catchcatch block block

trytry{{

Employee e;Employee e;e.GiveBonus(); e.GiveBonus(); // null reference// null reference

}}catchcatch{{

// Handle any exception// Handle any exception}}

How Exceptions are Executed?How Exceptions are Executed?

To catch an exception the To catch an exception the try-catchtry-catch block must be block must be usedused

A A try blocktry block is a section of the code that looks for is a section of the code that looks for an exceptionan exception

When an exception is raised, or thrown, within a When an exception is raised, or thrown, within a trytry block, an exception object is created and a block, an exception object is created and a search begins in the search begins in the catchcatch block block

When an exception occurs within that scope, the When an exception occurs within that scope, the control goes to the appropriate control goes to the appropriate catch blockcatch block (handler)(handler)

If no exception occurs, obviously the catch block If no exception occurs, obviously the catch block is never executedis never executed

After the catch block code is executed the rest of After the catch block code is executed the rest of the code in the program continues (is it OK?)the code in the program continues (is it OK?)

Catch block can also rethrow the exceptionCatch block can also rethrow the exception

Catching Specific ExceptionsCatching Specific Exceptionstrytry{{

Employee e;Employee e;e.GiveBonus(); e.GiveBonus(); // null reference// null reference

}}catch (NullReferenceException ex)catch (NullReferenceException ex){{

// Log the error// Log the errorthrow(ex);throw(ex);

}}

If the catch block can recover from the error that caused If the catch block can recover from the error that caused the exception, execution can continue after catch block. If it the exception, execution can continue after catch block. If it can't, then it must rethrow (shown in red color).can't, then it must rethrow (shown in red color).

If an exception is rethrown, the next catch block will be If an exception is rethrown, the next catch block will be checked. The check may continue in the call stack until a checked. The check may continue in the call stack until a proper handler is found. If none found, terminate!proper handler is found. If none found, terminate!

throwthrow statement statement

The The throwthrow statement is used to signal the statement is used to signal the occurrence of an anomalous situation occurrence of an anomalous situation /exception and to send the error object /exception and to send the error object back to the caller (raising an exception)back to the caller (raising an exception)

throw throw [[expressionexpression]];;

expressionexpression is an exception object is an exception object Usually the Usually the throwthrow statement is used with statement is used with

try-catch or try-finally statements. When try-catch or try-finally statements. When an exception is thrown, the program looks an exception is thrown, the program looks for the for the catchcatch statement that handles this statement that handles this exceptionexception

Example (Example (throwthrow))

using System;using System;public class ThrowTest public class ThrowTest {{ public static void Main() public static void Main() {{ string s = null;string s = null; if (s == null) if (s == null) {{ throw(new ArgumentNullException());throw(new ArgumentNullException()); }} // not executed// not executed

Console.Write("The string s is null"); Console.Write("The string s is null"); }}

}}

Output:Output:The following exception occurs:The following exception occurs:System.ArgumentNullExceptionSystem.ArgumentNullException

Example (Example (trytry - - catchcatch))using System;using System;class AddIntsclass AddInts{{

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

int a, b;int a, b;int c, d = 0;int c, d = 0;

Console.Write("Enter the first number (a): ");Console.Write("Enter the first number (a): ");a = System.Int32.Parse(Console.ReadLine());a = System.Int32.Parse(Console.ReadLine());

Console.Write("Enter the second number (b): ");Console.Write("Enter the second number (b): ");b = System.Int32.Parse(Console.ReadLine());b = System.Int32.Parse(Console.ReadLine());

c = a + b;c = a + b;

trytry{{

d = a / b;d = a / b;}}catch(Exception e)catch(Exception e){{

Console.WriteLine("Method: {0}", e.TargetSite);Console.WriteLine("Method: {0}", e.TargetSite);Console.WriteLine("Message: {0}", e.Message);Console.WriteLine("Message: {0}", e.Message);Console.WriteLine("Source: {0}", e.Source);Console.WriteLine("Source: {0}", e.Source);return;return;

}}Console.WriteLine("a + b = {0}", c);Console.WriteLine("a + b = {0}", c);Console.WriteLine("a / b = {0}", d);Console.WriteLine("a / b = {0}", d);

}}}}

Enter the first number (a): 28Enter the second number (b): 0Method: Void Main(System.String[]) //which method threw the exceptionMessage: Attempted to divide by zero.Source: AddInts

System.Exception Base ClassSystem.Exception Base Class Most of the memebers defined by Most of the memebers defined by

System.Exception are read-onlySystem.Exception are read-only

PropertyProperty MeaningMeaningHelpLinkHelpLink URL to a help fileURL to a help file

InnerExceptionInnerException details of previous exceptions that details of previous exceptions that caused the current exceptioncaused the current exception

MessageMessage returns the text describing the errorreturns the text describing the error

SourceSource name of the assembly that threw the name of the assembly that threw the exceptionexception

StackTraceStackTrace sequence of calls that triggered the sequence of calls that triggered the exceptionexception

TargetSiteTargetSite returns the MethodBase typereturns the MethodBase type

Example-2 : StackTraceExample-2 : StackTrace

StackTrace:StackTrace: Displays sequence of calls Displays sequence of calls that resulted in throwing the exception. that resulted in throwing the exception. We can follow the flow of the error's originWe can follow the flow of the error's origin

catch(Exception e)catch(Exception e)

{{

Console.WriteLine("Stack: {0}",e.StackTrace);Console.WriteLine("Stack: {0}",e.StackTrace);

}}

Example-3 : HelpLinkExample-3 : HelpLinktrytry{{

// create a new Exception object, passing a string// create a new Exception object, passing a string Exception myException = new Exception("myException");Exception myException = new Exception("myException");

// set the HelpLink and Source properties// set the HelpLink and Source propertiesmyException.HelpLink = "See the Readme.txt file"; myException.HelpLink = "See the Readme.txt file"; myException.Source = "My HelpLink Program"; myException.Source = "My HelpLink Program"; // throw the Exception object// throw the Exception objectthrow myException;throw myException;

}}catch (Exception e)catch (Exception e){{

// display the exception object's properties// display the exception object's propertiesConsole.WriteLine("HelpLink = " + e.HelpLink);Console.WriteLine("HelpLink = " + e.HelpLink);Console.WriteLine("Source = " + e.Source);Console.WriteLine("Source = " + e.Source);

}}HelpLink = See the Readme.txt fileSource = My HelpLink

Building Custom ExceptionsBuilding Custom Exceptions

Though the System level exceptions Though the System level exceptions are useful, sometimes it is necessary are useful, sometimes it is necessary to build user defined exceptionsto build user defined exceptions

Define a new user defined class Define a new user defined class derived from System.Exception derived from System.Exception

You may override any virtual You may override any virtual members defined in the parent classmembers defined in the parent class

۩۩ Square RootSquare Root

using System;using System;namespace CustomExceptionnamespace CustomException{{

class NegNumException : ApplicationExceptionclass NegNumException : ApplicationException{{

class NegNumException : ApplicationExceptionclass NegNumException : ApplicationException{{ public NegNumException() public NegNumException()

: base("SNG: Negative Number Exception"): base("SNG: Negative Number Exception") { }{ } public NegNumException(string msg) public NegNumException(string msg)

: base(msg): base(msg) { }{ } public NegNumException(string msg, Exception public NegNumException(string msg, Exception

inner) inner) : base(msg, inner): base(msg, inner)

{ }{ }}}

Square Root…Square Root…

class CustomExceptionclass CustomException{{

public double SqRoot(double n)public double SqRoot(double n){{

if (n < 0)if (n < 0)// calls 1-arg ctor.// calls 1-arg ctor.//throw new NegNumException//throw new NegNumException ("SNG: Negative Number not allowed");("SNG: Negative Number not allowed");// calls default ctor.// calls default ctor.throw new NegNumException();throw new NegNumException();return Math.Sqrt(n);return Math.Sqrt(n);

}}

Square Root…Square Root…public void SqRootTest()public void SqRootTest(){{

double n;double n;trytry{{

Console.Write("Enter a number: ");Console.Write("Enter a number: ");n = System.Double.Parse(Console.ReadLine()); n = System.Double.Parse(Console.ReadLine()); double result = SqRoot(n);double result = SqRoot(n);Console.WriteLine("Sq Root = {0}", result);Console.WriteLine("Sq Root = {0}", result);

}}catch(FormatException ex)catch(FormatException ex){{

Console.WriteLine(ex.Message);Console.WriteLine(ex.Message);}}catch(NegNumException ex)catch(NegNumException ex){{

Console.WriteLine(ex.Message);Console.WriteLine(ex.Message);}}

}}

Square Root…Square Root…

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

CustomException e = new CustomException(); CustomException e = new CustomException(); e.SqRootTest();e.SqRootTest();

}} }}}}

Multiple ExceptionsMultiple Exceptions

The code in the try block may trigger more The code in the try block may trigger more than one exception.than one exception.

Under these circumstances you can have Under these circumstances you can have more than one catch blockmore than one catch block

Exception will be processed by the nearest Exception will be processed by the nearest available catch block (Below example is available catch block (Below example is wrong!)wrong!)

Ex: Ex: try { … }try { … }

catch (Exception e) {…}catch (Exception e) {…}

catch (NegNumException e) {…}catch (NegNumException e) {…}

catch (ArgumentOutOfRangeException e) {…}catch (ArgumentOutOfRangeException e) {…}Unreachable

Other types of Exception HandlingOther types of Exception Handling

Generic catchGeneric catchtry {…}try {…}catchcatch{ … }{ … }

Rethrowing ExceptionsRethrowing Exceptionstry {…}try {…}catch (NegNumException e) catch (NegNumException e) { { // handle the error and pass the buck// handle the error and pass the buck throw e;throw e;} }

The The finallyfinally Block Block- The optional finally block will get executed always- The optional finally block will get executed always- Useful for cleaning up process or close the database files- Useful for cleaning up process or close the database files

No argument

rethrow the same exception

Garbage CollectionGarbage Collection

C# Programmers never directly deallocate an C# Programmers never directly deallocate an object from memory – so no 'object from memory – so no 'deletedelete' keyword' keyword

Rule: Allocate an object on to a managed heap Rule: Allocate an object on to a managed heap using 'using 'new'new' and forget about it! and forget about it!

How does .NET determine that an object is no How does .NET determine that an object is no longer needed? When it is unreachable by the longer needed? When it is unreachable by the current applicationcurrent application

Example: Example: public static int Main(string[] args)public static int Main(string[] args)

{{

Car c = new Car( );Car c = new Car( );

……..

}}

When the application shuts

down, object c may be destroyed.

Garbage CollectorGarbage Collector

CIL emits CIL emits newobjnewobj for for newnew .NET garbage collector maintains a new .NET garbage collector maintains a new

object pointer which indicates where the object pointer which indicates where the next object should be placed in the heapnext object should be placed in the heap

Assume c1, c2, and c3 are objects of type Assume c1, c2, and c3 are objects of type CarCar

c3c3 c2c2 c1c1 Unused heapUnused heap

next object pointer

Garbage Collector…Garbage Collector… If the managed heap does not have enough memory, If the managed heap does not have enough memory,

CLR does garbage collection. It frees the memory to CLR does garbage collection. It frees the memory to accommodate the new objectaccommodate the new object

Which object memory is to be removed – "no longer Which object memory is to be removed – "no longer needed" basisneeded" basis• Objects that have been recently allocated are most Objects that have been recently allocated are most

likely to be freedlikely to be freed• Objects that have lived the longest are least likely Objects that have lived the longest are least likely

to be become freeto be become free• Objects allocated together will be used togetherObjects allocated together will be used together

To get this idea CLR uses an object graph to know To get this idea CLR uses an object graph to know whether the objects are still in use. whether the objects are still in use.

The other objects which are no longer used – "severed The other objects which are no longer used – "severed roots" or unreachable objects are reclaimed and the roots" or unreachable objects are reclaimed and the memory is compacted with necessary object pointer memory is compacted with necessary object pointer adjustmentadjustment

Garbage Collector…Garbage Collector…

The Garbage Collector in .NET is known as The Garbage Collector in .NET is known as generationalgenerational garbage collector. garbage collector.

Allocated objects are sorted into three groups Allocated objects are sorted into three groups or generations:or generations:• generation 0: objects allocated most generation 0: objects allocated most

recentlyrecently• generation 1: Objects that survive a generation 1: Objects that survive a

garbage collection pass are moved into garbage collection pass are moved into generation 1generation 1

• generation 2: Objects that survive in generation 2: Objects that survive in generation 1 are moved into generation 2generation 1 are moved into generation 2

If no memory is available after compaction, If no memory is available after compaction, an an OutOfMemoryExceptionOutOfMemoryException is thrown is thrown

Finalizing a TypeFinalizing a Type The garbage collection process is nondeterministicThe garbage collection process is nondeterministic To release the memory in a timely manner, one possible To release the memory in a timely manner, one possible

solution is to override solution is to override System.Object.Finalize()System.Object.Finalize() method. method. We go for this only when C# types are using unmanaged types We go for this only when C# types are using unmanaged types

(Win32 APIs) Unmanaged resources: database connections and (Win32 APIs) Unmanaged resources: database connections and GDI GDI

Note that you can't override this method directly:Note that you can't override this method directly: public class FinalizedCarpublic class FinalizedCar {{

protected override void Finalize() { } protected override void Finalize() { } // Wrong// Wrong}}

protected void Finalize() protected void Finalize() // don't expose this method// don't expose this method{{

base.Finalize();base.Finalize();}}

Do not define both a destructor and Finalize method in the same Do not define both a destructor and Finalize method in the same classclass

Indirectly Invoking Finalize()Indirectly Invoking Finalize() When an Application domain is unloaded by CLR, the When an Application domain is unloaded by CLR, the Finalize()Finalize()

method is invoked for all finalizable objectsmethod is invoked for all finalizable objectsclass FinalizedCarclass FinalizedCar{ {

~FinalizedCar()~FinalizedCar(){ Console.WriteLine("Finalizing"); }{ Console.WriteLine("Finalizing"); } // 3// 3class FinalizeAppclass FinalizeApp{{

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

Console.WriteLine("Object creation");Console.WriteLine("Object creation"); // 1// 1FinalizedCar fc = new FinalizedCar();FinalizedCar fc = new FinalizedCar();Console.WriteLine("Exiting Main");Console.WriteLine("Exiting Main"); // 2// 2

}}}}

}}

Instead of using a finalizer (because it is costly), you can Instead of using a finalizer (because it is costly), you can expose the Dispose() methodexpose the Dispose() method

Dispose with Dispose with usingusing With the presence of the With the presence of the usingusing statement, which statement, which

opens a scope at the end of which a given object opens a scope at the end of which a given object will be disposed, regardless of whether the scope will be disposed, regardless of whether the scope is exited normally or via an exception. is exited normally or via an exception.

using( Pen myPen = new Pen(Color.Red) )using( Pen myPen = new Pen(Color.Red) ){{ // Do stuff with myPen// Do stuff with myPen}}

When objects are of the same type, you may put When objects are of the same type, you may put them all inside the same them all inside the same usingusing statement: statement:

using( Pen myRedPen = new Pen(Color.Red),using( Pen myRedPen = new Pen(Color.Red),myBluePen = new Pen(Color.Blue) )myBluePen = new Pen(Color.Blue) )

{{ // Do stuff with both pens// Do stuff with both pens}}

Dispose with Dispose with usingusing For instance, you'll need a Font and a Brush if you want to use the For instance, you'll need a Font and a Brush if you want to use the

Graphics.DrawString method to paint some text. Unfortunately, Graphics.DrawString method to paint some text. Unfortunately, here's where the here's where the usingusing statement starts to break down, because statement starts to break down, because the following code generates a compile error: the following code generates a compile error:

using( Font myFont = new Font("Arial", 16),using( Font myFont = new Font("Arial", 16), SolidBrush myBrush = new SolidBrush(Color.Blue) )SolidBrush myBrush = new SolidBrush(Color.Blue) ){{ // COMPILE ERROR!// COMPILE ERROR!}}

That snippet doesn't compile because C# doesn't let you have That snippet doesn't compile because C# doesn't let you have more than one type in a single more than one type in a single usingusing statement. So, your next statement. So, your next alternative is to nest alternative is to nest usingusing statements like this: statements like this:

using( Font myFont = new Font("Arial", 16) )using( Font myFont = new Font("Arial", 16) ){{ using( SolidBrush myBrush = new SolidBrush(Color.Blue) )using( SolidBrush myBrush = new SolidBrush(Color.Blue) ) {{ {{ // Do stuff with a font and a brush// Do stuff with a font and a brush }} }}}}

Dispose with Dispose with usingusing

But use of more than a couple of But use of more than a couple of levels of nesting, and your code gets levels of nesting, and your code gets ugly pretty quicklyugly pretty quickly

Hence, we must search for a better Hence, we must search for a better solutionsolution

Implementing IDisposableImplementing IDisposable

Creating and properly disposing of an Creating and properly disposing of an object requires several lines of correctly object requires several lines of correctly written code.written code.

C# provides an automated solution based C# provides an automated solution based on on IDisposeIDispose interface interface

IDisposeIDispose interface provided in .NET is for interface provided in .NET is for symmetry among all objects that supports symmetry among all objects that supports an explicit destructionan explicit destruction

IDispose Implementation FlowIDispose Implementation Flow

Implementing IDisposable…Implementing IDisposable…

public class MyClass : IDisposablepublic class MyClass : IDisposable{{

public void Dispose()public void Dispose(){{

Console.WriteLine("Custom cleaning Console.WriteLine("Custom cleaning process");process");}}

}}

public class IDisposeApppublic class IDisposeApp{{

public static void Main(string[] args)public static void Main(string[] args){{

MyClass m = new MyClass();MyClass m = new MyClass(); m.Dispose();m.Dispose();

}}}}

ExampleExamplepublic class ClassBeingTested : IDisposablepublic class ClassBeingTested : IDisposable{{ private bool disposed=false;private bool disposed=false; private Image img=null;private Image img=null; public Image Imagepublic Image Image {{ get {return img;}get {return img;} }} // the constructor// the constructor public ClassBeingTested()public ClassBeingTested() {{ Trace.WriteLine("ClassBeingTested: Constructor");Trace.WriteLine("ClassBeingTested: Constructor"); }} // the destructor// the destructor ~ClassBeingTested()~ClassBeingTested() {{ Trace.WriteLine("ClassBeingTested: Destructor");Trace.WriteLine("ClassBeingTested: Destructor"); // call Dispose with false. Since we're in the// call Dispose with false. Since we're in the // destructor call, the managed resources will be// destructor call, the managed resources will be // disposed of anyways.// disposed of anyways. Dispose(false);Dispose(false); } }

public void Dispose()public void Dispose() {{

Trace.WriteLine("ClassBeingTested: Dispose");Trace.WriteLine("ClassBeingTested: Dispose"); // dispose of the managed and unmanaged resources// dispose of the managed and unmanaged resources Dispose(true);Dispose(true);

// tell the GC that the Finalize process no longer needs// tell the GC that the Finalize process no longer needs // to be run for this object.// to be run for this object. GC.SuppressFinalize(this);GC.SuppressFinalize(this);

}}

protected virtual void Dispose(bool disposeManagedResources)protected virtual void Dispose(bool disposeManagedResources) {{ // process only if mananged and unmanaged resources have not been disposed of.// process only if mananged and unmanaged resources have not been disposed of. if (!this.disposed)if (!this.disposed) {{ Trace.WriteLine("ClassBeingTested: Resources not disposed");Trace.WriteLine("ClassBeingTested: Resources not disposed"); if (disposeManagedResources)if (disposeManagedResources) {{ Trace.WriteLine("ClassBeingTested: Disposing managed resources");Trace.WriteLine("ClassBeingTested: Disposing managed resources"); // dispose managed resources// dispose managed resources if (img != null)if (img != null) {{ img.Dispose();img.Dispose(); img=null;img=null; }} }} // dispose unmanaged resources// dispose unmanaged resources Trace.WriteLine("ClassBeingTested: Disposing unmanaged resouces");Trace.WriteLine("ClassBeingTested: Disposing unmanaged resouces"); disposed=true;disposed=true; }} elseelse {{ Trace.WriteLine("ClassBeingTested: Resources already disposed");Trace.WriteLine("ClassBeingTested: Resources already disposed"); }} }}

End of Chapter - 5End of Chapter - 5

For more details on IDispose For more details on IDispose implementation, please refer to:implementation, please refer to:

www.codeproject.com/csharp/IDispose.aspwww.codeproject.com/csharp/IDispose.asp C# How to Program by DEITEL & DEITELC# How to Program by DEITEL & DEITEL