Mod 3 Dotnet Notes

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 47

Module 3 .

Net framework for application development

MODULE 3 : Understanding the C# object model(Contd)


Chapter 11: Understanding parameter arrays
Using array arguments
 Suppose we want to write a method to determine the minimum value in a set of values
passed as parameters.
 One way is to use an array. For example, to find the smallest of several int values, we
could write a static method named Min with a single parameter representing an array of
int values:
class Util
{
public static int Min(int[] paramList)
{
// Verify that the caller has provided at least one parameter.
// If not, throw an ArgumentException exception – it is not possible
// to find the smallest value in an empty list.
if (paramList == null || paramList.Length == 0)
{
throw new ArgumentException("Util.Min: not enough arguments");
}
// Set the current minimum value found in the list of parameters to the first item
int currentMin = paramList[0];
// Iterate through the list of parameters, searching to see whether any of them
// are smaller than the value held in currentMin
foreach (int i in paramList)
{
// If the loop finds an item that is smaller than the value held in
// currentMin, then set currentMin to this value
if (i < currentMin)
{
currentMin = i;

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 1


Module 3 .Net framework for application development

}
}
// At the end of the loop, currentMin holds the value of the smallest
// item in the list of parameters, so return this value.
return currentMin;
}
}
Note:
 The ArgumentException class is specifically designed to be thrown by a method if the
arguments supplied do not meet the requirements of the method.
 To use the Min method to find the minimum of two int variables named first and second,
we can write this:
int[] array = new int[2];
array[0] = first;
array[1] = second;
int min = Util.Min(array);
 And to use the Min method to find the minimum of three int variables (named first,
second, and third), write this:
int[] array = new int[3];
array[0] = first;
array[1] = second;
array[2] = third;
int min = Util.Min(array);
 We can see that this solution avoids the need for a large number of overloads, but we
have to write additional code to populate the array.
 The solution is to get the compiler to write some of this code for the user by using a
params array as the parameter to the Min method.

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 2


Module 3 .Net framework for application development

Declaring a params array


 Using a params array, we can pass a variable number of arguments to a method.
 We indicate a params array by using the params keyword as an array parameter modifier
when we define the method parameters.
 For example, here’s Min again —this time with its array parameter declared as a params
array:
class Util
{
public static int Min(params int[] paramList)
{
// code exactly as before
}
}
 The effect of the params keyword on the Min method is that it allows to call the method
by using any number of integer arguments without worrying about creating an array. For
example, to find the minimum of two integer values, simply write this:
int min = Util.Min(first, second);
 The compiler translates this call into code similar to this:
int[] array = new int[2];
array[0] = first;
array[1] = second;
int min = Util.Min(array);
 To find the minimum of three integer values, write the code shown here, which is also
converted by the compiler to the corresponding code that uses an array:
int min = Util.Min(first, second, third);
 Both calls to Min (one call with two arguments and the other with three arguments)
resolve to the same Min method with the params keyword.
 And, we can call this Min method with any number of int arguments. The compiler just
counts the number of int arguments, creates an int array of that size, fills the array with
the arguments, and then calls the method by passing the single array parameter.

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 3


Module 3 .Net framework for application development

Note:
 Can’t use the params keyword with multidimensional arrays. The cod in the following
example will not compile:
// compile-time error
public static int Min(params int[,] table)
...
 Can’t overload a method based solely on the params keyword. The params keyword does
not form part of a method’s signature, as shown in this example. Here, the compiler
would not be able to distinguish between these methods in code that calls them:
// compile-time error: duplicate declaration
public static int Min(int[] paramList)
...
public static int Min(params int[] paramList)
...
 Not allowed to specify the ref or out modifier with params arrays, as shown in this
example:
// compile-time errors
public static int Min(ref params int[] paramList)
...
public static int Min(out params int[] paramList)
...
 A params array must be the last parameter. (This means that you can have only one
params array per method.) Consider this example:
// compile-time error
public static int Min(params int[] paramList, int i)
...
 A non-params method always takes priority over a params method. This means that we
can still create an overloaded version of a method for the common cases, such as in the
following example:
public static int Min(int leftHandSide, int rightHandSide)
...

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 4


Module 3 .Net framework for application development

public static int Min(params int[] paramList)


...
The first version of the Min method is used when it’s called using two int arguments. The second
version is used if any other number of int arguments is supplied. This includes the case in which
the method is called with no arguments. Adding the non-params array method might be a useful
optimization technique because the compiler won’t have to create and populate so many arrays.

Using params object[]


 A parameter array of type int is very useful. With it, we can pass any number of
int arguments in a method call.
 However, what if not only the number of arguments varies but also the argument type?
C# has a way to solve this problem, too.
 The technique is based on the facts that object is the root of all classes and that the
compiler can generate code that converts value types (things that aren’t classes) to objects
by using boxing
 We can use a parameters array of type object to declare a method that accepts any
number of object arguments, allowing the arguments passed in to be of any type. Look at
this example:
class Black
{
public static void Hle(params object[] paramList)
...
}
 We can pass the method no arguments at all, in which case the compiler will pass an
object array whose length is 0:
Black.Hle();
// converted to Black.Hle(new object[0]);
 We can call the Black.Hle method by passing null as the argument. An array is a
reference type, so you’re allowed to initialize an array with null:
Black.Hle(null);

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 5


Module 3 .Net framework for application development

 We can pass the Black.Hle method an actual array. In other words, you can manually
create the array normally generated by the compiler:
object[] array = new object[2];
array[0] = "forty two";
array[1] = 42;
Black.Hle(array);
 We can pass the Black.Hle method arguments of different types, and these arguments will
automatically be wrapped inside an object array:
Black.Hle("forty two", 42);
//converted to Black.Hle(new object[]{"forty two", 42});

Using a params array


In the following program, we will implement and test a static method named Sum. The purpose
of this method is to calculate the sum of a variable number of int arguments passed to it,
returning the result as an int. Do this by writing Sum to take a params int[] parameter.
class Util
{
public static int Sum(params int[] paramList)
{
if (paramList == null)
{
throw new ArgumentException("Util.Sum: null parameter list");
}
if (paramList.Length == 0)
{
throw new ArgumentException("Util.Sum: empty parameter
list");
}
int sumTotal = 0;
foreach (int i in paramList)
{
sumTotal += i;
}
return sumTotal;
}

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 6


Module 3 .Net framework for application development

public static void Main()


{
Console.WriteLine(Util.Sum(null));
//output: Exception: Util.Sum: null parameter list
Console.WriteLine(Util.Sum());
//output: Exception: Util.Sum: empty parameter list
Console.WriteLine(Util.Sum(10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
//output: 55
Console.WriteLine(Util.Sum(3, 2, 1));
//output: 6
}
}//end of class

Comparing parameter arrays and optional parameters


The fundamental differences between them:
 A method that takes optional parameters still has a fixed parameter list, and
we cannot pass an arbitrary list of arguments. The compiler generates code that inserts the
default values onto the stack for any missing arguments before the method runs, and the method
is not aware of which of the arguments are provided by the caller and which are compiler-
generated defaults.
 A method that uses a parameter array effectively has a completely arbitrary list of
parameters, and none of them has a default value. Furthermore, the method can determine
exactly how many arguments the caller provided.
 Generally, we use parameter arrays for methods that can take any number of parameters
(including none), whereas we use optional parameters only where it is not convenient to force a
caller to provide an argument for every parameter.
 If we define a method that takes a parameter list and provide an overload that takes
optional parameters, it is not always immediately apparent which version of the method will be
called if the argument list in the calling statement matches both method signatures. Given a

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 7


Module 3 .Net framework for application development

choice between a method that takes optional parameters and a method that takes a parameter list,
the C# compiler will use the method that takes optional parameters.
 Consider the following example:
class Util
{
public static int Sum(params int[] paramList)
{
Console.WriteLine("Using parameter list");
if (paramList == null)
{
throw new ArgumentException("Util.Sum: null parameter list");
}
if (paramList.Length == 0)
{
throw new ArgumentException("Util.Sum: empty parameter
list");
}
int sumTotal = 0;
foreach (int i in paramList)
{
sumTotal += i;
}
return sumTotal;
}
public static int Sum(int param1 = 0, int param2 = 0, int param3 = 0, int
param4 = 0)
{
Console.WriteLine("Using optional parameters");
int sumTotal = param1 + param2 + param3 + param4;
return sumTotal;
}
public static void Main()
{
Console.WriteLine(Util.Sum(2, 4, 6, 8));
//output: Using optional parameters
// 20
Console.WriteLine(Util.Sum(2, 4, 6));
//output: Using optional parameters

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 8


Module 3 .Net framework for application development

// 12
Console.WriteLine(Util.Sum(10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
//output: Using parameter list
// 55
}

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 9


Module 3 .Net framework for application development

MODULE 3 : Understanding the C# object model(Contd)


Chapter 12: Working with inheritance

What is inheritance?

 Inheritance enables the language’s ability to allows to build new class definitions based
on existing class definitions.
 Inheritance allows to extend the behavior of a base (or parent) class by enabling a
subclass to inherit core functionality (also called a derived class or child class)

Using inheritance

 We declare that a class inherits from another class by using the following syntax:
class DerivedClass : BaseClass
{
...
}
 The derived class inherits from the base class, and the methods in the base class become
part of the derived class.
 In C#, a class is allowed to derive from, at most, one base class; a class is not allowed to
derive from two or more classes.
 However, unless DerivedClass is declared as sealed, we can use the same syntax to
derive other classes that inherit from DerivedClass.
class DerivedSubClass : DerivedClass
{
...
}
 Consider an example of declaring the Mammal class as follows. The methods Breathe
are common to all mammals.
class Mammal
{
public void Breathe()
{
...

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 10


Module 3 .Net framework for application development

}
...
}
 We could then define new classes for each different type of mammal, adding more
methods as necessary, such as in the following example:
class Horse : Mammal
{
...
public void Trot()
{
...
}
}
class Whale : Mammal
{
...
public void Swim()
{
...
}
}
Note:
 We cannot explicitly specify whether the inheritance is public, private, or protected. C#
inheritance is always implicitly public.
 use of the colon and that there is no extends keyword.
 If we create a Horse object in your application, we can call the Trot, Breathe methods:
Horse myHorse = new Horse();
myHorse.Trot();
myHorse.Breathe();
Similarly, you can create a Whale object, but this time we can call the Swim, Breathe
methods; Trot is not available because it is defined only in the Horse class.

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 11


Module 3 .Net framework for application development

The System.Object class revisited


 The System.Object class is the root class of all classes.
 All classes implicitly derive from System.Object. Consequently, the C# compiler silently
rewrites the Mammal class as the following code:
class Mammal : System.Object
{
...
}
 Any methods in the System.Object class are automatically passed down the chain of
inheritance to classes that derive from Mammal, such as Horse and Whale.
 In practical terms, this means that all classes that we define automatically inherit all the
features of the System.Object class.

Calling base-class constructors


 In addition to the methods that it inherits, a derived class automatically contains all the
fields from the base class.
 These fields usually require initialization when an object is created. You typically
perform this kind of initialization in a constructor. Remember that all classes have at least
one constructor. (If you don’t provide one, the compiler generates a default constructor
for you.)
 It is good practice for a constructor in a derived class to call the constructor for its base
class as part of the initialization, which enables the base-class constructor to perform any
additional initialization that it requires.
 We can specify the base keyword to call a base-class constructor when we define a
constructor for an inheriting class, as shown in this example:
class Mammal // base class
{
public Mammal(string name) // constructor for base class
{
...

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 12


Module 3 .Net framework for application development

}
...
}
class Horse : Mammal // derived class
{
public Horse(string name) : base(name) // calls Mammal(name)
{
...
}
...
}
 If we don’t explicitly call a base-class constructor in a derived-class constructor, the
compiler attempts to silently insert a call to the base class’s default constructor before
executing the code in the derived-class constructor.
 Taking the earlier example, the compiler rewrites this
class Horse : Mammal
{
public Horse(string name)
{
...
}
...
}
as this: class Horse : Mammal
{
public Horse(string name) : base()
{
...
}
...
}

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 13


Module 3 .Net framework for application development

 This works if Mammal has a public default constructor. However, not all classes have a
public default constructor (for example, remember that the compiler generates a default
constructor only if we don’t write any nondefault constructors), in which case forgetting
to call the correct base-class constructor results in a compile-time error.

Assigning classes
 We can declare a variable by using a class type and the new keyword to create an object.
 The type-checking rules of C# prevent from assigning an object of one type to a variable
declared as a different type. For example, given the definitions of the Mammal, Horse,
and Whale classes shown here, the code that follows these definitions is illegal:
class Mammal
{
...
}
class Horse : Mammal
{
...
}
class Whale : Mammal
{
...
}
Horse myHorse = new Horse( );
Whale myWhale = myHorse; // error - different types
 However, it is possible to refer to an object from a variable of a different type as long as
the type used is a class that is higher up the inheritance hierarchy. So the following
statements are legal:
Horse myHorse = new Horse( );
Mammal myMammal = myHorse; // legal, Mammal is the base class of Horse

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 14


Module 3 .Net framework for application development

 If we think about it in logical terms, all Horses are Mammals, we can safely assign an
object of type Horse to a variable of type Mammal.
 We can also make a Mammal variable refer to a Whale object. There is one significant
limitation, however: When referring to a Horse or Whale object by using a Mammal
variable, we can access only methods and fields that are defined by the Mammal class.
Any additional methods defined by the Horse or Whale class are not visible through the
Mammal class.
Horse myHorse = new Horse(...);
Mammal myMammal = myHorse;
myMammal.Breathe(); // OK - Breathe is part of the Mammal
class myMammal.Trot(); // error - Trot is not part of the Mammal class

Declaring virtual methods

 Polymorphism provides a way for a subclass to customize how it implements a method


defined by its base class.
 If a base class wishes to define a method that may be overridden by a subclass, it must
specify the method as virtual:
 A method that is intended to be overridden is called a virtual method.
 Overriding a method is a mechanism for providing different implementations of the
same method—the methods are all related because they are intended to perform the same
task, but in a class-specific manner.

Declaring override methods

 If a base class declares that a method is virtual, a derived class can use the override
keyword to declare another implementation of that method,
 The new implementation of the method in the derived class can call the original
implementation of the method in the base class by using the base keyword
 Program illustrating virtual and override keywords:

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 15


Module 3 .Net framework for application development

Using System;
public class Shape

// Shapes can be assigned a friendly petname.


protected string petName;

// Constructors.

public Shape(){ petName = "NoName"; }

public Shape(string s) { petName = s;}

// Draw() is virtual and may be overridden. public


virtual void Draw()
{
Console.WriteLine("Shape.Draw()");

}//end of shape class

// Circle DOES NOT override Draw().


// public class Circle : Shape
{
public Circle() { }

public Circle(string name): base(name)

{}

}//END OF CLASS CIRCLE

// Hexagon DOES override Draw().


public class Hexagon : Shape

public Hexagon(){ }

public Hexagon(string name):base(name) { }


public override void Draw() {

Console.WriteLine("Drawing {0} the Hexagon", petName);

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 16


Module 3 .Net framework for application development

}//END OF CLASS HEXAGON

Class Test {

// The Circle object did not override the base class implementation of Draw().
static void Main(string[] args)
{
Hexagon hex = new Hexagon("Beth");

hex.Draw();

// Using base class implementation.

cir.Draw();

}
}
There are some important rules you must follow when we declare polymorphic methods by
using the virtual and override keywords:
 A virtual method cannot be private; it is intended to be exposed to other classes through
inheritance. Similarly, override methods cannot be private because a class cannot change
the protection level of a method that it inherits. However, override methods can have a
special form of privacy known as protected access
 The signatures of the virtual and override methods must be identical; they must have the
same name, number, and types of parameters. In addition, both methods must return the
same type
 We can only override a virtual method. If the base class method is not virtual and you try
to override it, you’ll get a compile-time error. This is sensible; it should be up to the
designer of the base class to decide whether its methods can be overridden.
 If the derived class does not declare the method by using the override keyword, it does
not override the base class method; it hides the method. In other words, it becomes an
implementation of a completely different method that happens to have the same name. As

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 17


Module 3 .Net framework for application development

before, this will cause a compile time warning, which can be silenced by using the new
keyword
 An override method is implicitly virtual and can itself be overridden in a further derived
class. However, you are not allowed to explicitly declare that an override method is
virtual by using the virtual keyword.

Regarding Multiple Base Classes

 C# demands that a given class have exactly one direct base class. Therefore, it is not
possible to have a single type with two or more base classes (this technique is known as
multiple inheritance or simply MI).
 C# does allow a given type to implement any number of discrete interfaces. In this way, a
C# class can exhibit a number of behaviors while avoiding the problems associated with
classic MI.
 It is permissible to configure a single interface to derive from multiple interfaces.

Keeping Family Secrets: The protected Keyword

 Public items are directly accessible from anywhere, while private items cannot be
accessed from any object beyond the class that has defined it.
 When a base class defines protected data or protected members, it is able to create a set of
items that can be accessed directly by any descendent. If you wish to allow the
SalesPerson and Manager child classes to directly access the data sector defined by
Employee, we can update the original Employee class definition as follows:

// Protected state data.


public class Employee
{

// Child classes can directly access this information. Object users cannot.
protected string fullName;

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 18


Module 3 .Net framework for application development

protected int empID;


protected float currPay;
protected string empSSN;
protected int empAge;

 The benefit of defining protected members in a base class is that derived types no longer
have to access the data using public methods or properties.
 The object user is concerned; protected data is regarded as private (as the user is
“outside” of the family). Therefore, the following is illegal:

static void Main(string[] args)

//Error! Can't access protected data from object instance.


Employee emp = new Employee();
emp.empSSN = "111-11-1111";

Preventing Inheritance: Sealed Classes


 When you establish base class/subclass relationships, we are able to leverage the
behavior of existing types. For example, assume you have added yet another class to your
employee hierarchy that extends the existing SalesPerson type.

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 19


Module 3 .Net framework for application development

 PTSalesPerson is a class representing (of course) a part-time salesperson.


 To prevent others from extending a class, make use of the C# sealed keyword:

//Ensure that PTSalesPerson cannot act as a base class to others.


public sealed class PTSalesPerson : SalesPerson
{

public PTSalesPerson(string fullName, int age, int


empID, float currPay, string ssn, int numbOfSales):
base(fullName, age, empID, currPay, ssn, numbOfSales)

// Interesting constructor logic...


}

// Other interesting members...


}

 Because PTSalesPerson is sealed, it cannot serve as a base class to any other type. If
extended PTSalesPerson, receive a compiler error:

// Compiler error!

public class ReallyPTSalesPerson : PTSalesPerson { ... }

 The sealed keyword is most useful when creating stand-alone utility classes.
 The sealed keyword can also be applied to type members to prevent virtual members
from being further overridden by derived types.
 This can be helpful when we do not wish to seal an entire class, just a few select methods
or properties.
 For example, PTSalesPerson class to be extended by other classes but make sure those
classes did not further override the virtual GiveBonus(), we could write the following:

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 20


Module 3 .Net framework for application development

// This class can be extended;

// however, GiveBonus() cannot be overriden by derived classes.


public class PTSalesPerson : SalesPerson

...

public override sealed void GiveBonus(float amount)

...

Abstract Classes
 Abstract classes are one of the essential behaviors provided by .NET. Commonly, we
would like to make classes that only represent base classes, and don’t want anyone to
create objects of these class types.
 We can make use of abstract classes to implement such functionality in C# using the
modifier 'abstract'.
 An abstract class means that, no object of this class can be instantiated, but can make
derivations of this.
 An example of an abstract class declaration is:
abstract class absClass
{}
 An abstract class can contain either abstract methods or non abstract methods. Abstract
members do not have any implementation in the abstract class, but the same has to be
provided in its derived class.
 An example of an abstract method:

abstract class absClass

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 21


Module 3 .Net framework for application development

public abstract void abstractMethod();

 Also, note that an abstract class does not mean that it should contain abstract members.
Even we can have an abstract class only with non abstract members. For example:

abstract class absClass


{
public void NonAbstractMethod()
{
Console.WriteLine("NonAbstract Method");
}
}

A sample program that explains abstract classes:

using System;
namespace abstractSample
{
//Creating an Abstract Class
abstract class absClass
{
//A Non abstract method
public int AddTwoNumbers(int Num1, int Num2)
{
return Num1 + Num2;
}

//An abstract method, to be


//overridden in derived class
public abstract int MultiplyTwoNumbers(int Num1, int Num2);
}

//A Child Class of absClass


class absDerived:absClass
{
static void Main(string[] args)
{
//You can create an
//instance of the derived class

absDerived calculate = new absDerived();


int added = calculate.AddTwoNumbers(10,20);
int multiplied = calculate.MultiplyTwoNumbers(10,20);
Console.WriteLine("Added : {0},
Multiplied : {1}", added, multiplied);
}

//using override keyword,


//implementing the abstract method
//MultiplyTwoNumbers
public override int MultiplyTwoNumbers(int Num1, int Num2)

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 22


Module 3 .Net framework for application development

{
return Num1 * Num2;
}
}
}

 In the above sample, we can see that the abstract class absClass contains two
methods AddTwoNumbers and MultiplyTwoNumbers. AddTwoNumbers is a non
abstract method which contains implementation andMultiplyTwoNumbers is an abstract
method that does not contain implementation.
 The class absDerived is derived from absClass and the MultiplyTwoNumbers is
implemented onabsDerived. Within the Main, an instance (calculate) of the absDerived is
created, and calls AddTwoNumbersand MultiplyTwoNumbers. You can derive an
abstract class from another abstract class. In that case, in the child class it is optional to
make the implementation of the abstract methods of the parent class.

Important rules applied to abstract classes

 An abstract class cannot be a sealed class. I.e. the following declaration is incorrect.

//Incorrect
abstract sealed class absClass
{
}

 Declaration of abstract methods are only allowed in abstract classes.


 An abstract method cannot be private.

//Incorrect
private abstract int MultiplyTwoNumbers();

 The access modifier of the abstract method should be same in both the abstract class and
its derived class. If you declare an abstract method as protected, it should be protected in
its derived class. Otherwise, the compiler will raise an error.

An abstract method cannot have the modifier virtual. Because an abstract method is implicitly
virtual.

//Incorrect
public abstract virtual int MultiplyTwoNumbers();

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 23


Module 3 .Net framework for application development

 An abstract member cannot be static.

//Incorrect
public abstract static int MultiplyTwoNumbers();

Member Hiding- using new methods


 C# provides a facility that is the logical opposite of method overriding: member hiding.
 If a derived class redeclares an identical member inherited from a base class, the derived
class has hidden (or shadowed) the parent’s member.
 For example assume you receive a class named ThreeDCircle from a coworker (or
classmate) that currently derives from System.Object:

public class ThreeDCircle

public void Draw()

Console.WriteLine("Drawing a 3D Circle");

 You figure that a ThreeDCircle “is-a” Circle, so you derive from your existing Circle
type:
public class ThreeDCircle : Circle

public void Draw()

Console.WriteLine("Drawing a 3D Circle");

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 24


Module 3 .Net framework for application development

 Once you recompile, you find the following warning shown in Visual Studio 2005 (see
Figure below).

To address this issue, you have two options.

1. You could simply update the parent’s version of Draw() using the override keyword.
With this approach, the ThreeDCircle type is able to extend the parent’s default behavior
as required.

2. You can prefix the new keyword to the offending Draw() member of the
ThreeDCircle type. Doing so explicitly states that the derived type’s implemention is
intentionally designed to hide the parent’s version.

// This class extends Circle and hides the inherited Draw()


method.
public class ThreeDCircle : Circle

// Hide any Draw() implementation above me.

public new void Draw()

Console.WriteLine("Drawing a 3D Circle");

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 25


Module 3 .Net framework for application development

 The new can also apply keyword to any member type inherited from a base class (field,
constant, static member, property, etc.).
 For example:

public class ThreeDCircle : Circle

new protected string petName;

new public void Draw()

Console.WriteLine("Drawing a 3D Circle");

 Finally, be aware that it is still possible to trigger the base class implementation of a
shadowed member using an explicit cast (described in the next section). For example:

static void Main(string[] args)

ThreeDCircle o = new ThreeDCircle();

o.Draw(); // Calls ThreeDCircle.Draw()

((Circle)o).Draw(); // Calls Circle.Draw()

Using Extension Methods in C#

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 26


Module 3 .Net framework for application development

 Extension methods enable you to add methods to existing types without creating a new
derived type, recompiling, or otherwise modifying the original type.
 An extension method is a special kind of static method, but they are called as if they were
instance methods on the extended type.

How to use extension methods?

 An extension method is a static method of a static class, where the "this" modifier is
applied to the first parameter. The type of the first parameter will be the type that is
extended.
 Extension methods are only in scope when you explicitly import the namespace into your
source code with a using directive.
 Like: suppose we have a class like bellow:

1. public class Class1 {


2. public string Display() {
3. return ("I m in Display");
4. }
5.
6. public string Print() {
7. return ("I m in Print");
8. }

 Now we need to extend the definition of this class, so create a static class to create an
extension method like:

1. public static class XX {


2. public static void NewMethod(this Class1 ob) {
3. Console.WriteLine("Hello I m extended method");
4. }
5. }

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 27


Module 3 .Net framework for application development

 Here a method is NewMethod is created with a parameter using this to define which type
of data need to be extended, now let’s see how to use this function.

1. class Program {
2. static void Main(string[] args) {
3. Class1 ob = new Class1();
4. ob.Display();
5. ob.Print();
6. ob.NewMethod();
7. Console.ReadKey();
8. }
9. }

Output will be:

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 28


Module 3 .Net framework for application development

MODULE 3 : Understanding the C# object model(Contd)


Chapter 13: Creating Interfaces
Defining Interfaces using C#
 An interface is a named collection of semantically abstract members. The specific
members defined by an interface depend on the exact behaviour it is modelling.

 An interface expresses a behaviour that a given class or structure may choose to support.

 An interface is defined using C# interface keyword.

 Interfaces never specify a base class, not even System.Object.

 Interfaces contain members that don’t have access modifiers. All interface members are
implicitly public and abstract.

public interface IPointy

int Points{get;}

int GetNumberOfSides();

}

.NET interface types can also define any number of properties.
You cannot instantiate an interface as you would do for a class or structure.
Interfaces are implemented by a class or structure.

Implementing an interface in C#

When a class or structure chooses to extend its functionality by supporting interface
types, it does so by using a comma delimited list in the type definition.
//A class implementing an Interface

public class ExampleClass : IPointy,IExampleInterface

{…}

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 29


Module 3 .Net framework for application development

The direct base class must be the first item listed after the colon operator. Say, if we are
implementing System.Object or class MyBaseClass, then it must be the first to
implement.
public class ExampleClass : System.Object,IPointy
{…}

public class ExampleClass : MyBaseClass,IPointy

{…}

Implementing an interface is all-or-nothing proposition.

public class Triangle : IPointy

public int Points

{ get { return 3;}}

public int GetNumberOf Sides()

{ return 3; }

class Hexagon : Shape,IPointy

public Hexagon() { }

public Hexagon(string name) : base(name) { }

public override void Draw() { }

public int Points

get

{ return 6; }

public int GetNumberOfSides()

{
Mamatha A, Asst Prof, Dept of ISE,SVIT Page 30
Module 3 .Net framework for application development

return 6;

Invoking Interface Members at Object Level



To interact with the functionality supplied by a given interface, invoke the members
directly from the object level.

public static void Main()

Hexagon hex = new Hexagon();

Console.WriteLine(hex.Points);

}

We can dynamically determine the set of interfaces supported by a type by making use of
an explicit cast. If a type does not support a requested interface, you receive an
InvalidCastException.

public static void Main()

Hexagon hex = new Hexagon();

IPointy Ipt;

try

Ipt = (IPointy)hex;

Console.WriteLine(Ipt.Points);

catch(InvalidCastException)

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 31


Module 3 .Net framework for application development

Console.WriteLine(ex.Message);

Obtaining Interface References: The as keyword


You can determine whether a given type supports an interface is to make use of the as
keyword.
If the object can be treated as a specified interface, you are returned a reference to the
interface in question. If not, a null reference is received.
public static void Main()

Hexagon hex = new Hexagon();

IPointy Ipt = hex as IPointy;

if(Ipt != null)

Console.WriteLine(Ipt.Points);

else

Console.WriteLine(“Not IPointy”);

Obtaining Interface References: The is keyword

If the object in question is not compatible with the specified interface, you are returned
the value false.
If the type is compatible with the interface in question, you can safely call the members
without needing to make use of try/catch logic.
public static void Main()

Hexagon hex = new Hexagon();

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 32


Module 3 .Net framework for application development

if(hex is IPointy)

Console.WriteLine(((IPointy)hex).Points);

else

Console.WriteLine(“No IPointy”);

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 33


Module 3 .Net framework for application development

MODULE 3 : Understanding the C# object model(Contd)


Chapter 14: Using Garbage Collection and Resource Management

Garbage Collection

One of the great strengths of the Microsoft Visual C# language is that it makes a fundamental
distinction between values and objects. Values and objects are different.

Comparing Values and Objects

The distinction between values and objects is discussed below:

 A value is an instance of a value type (an enumeration or a struct) whereas an object is an


instance of a reference type (an array, a class, or a delegate):

int i = 42; // i is a value


TextBox box = new TextBox(); // box refers to an object

 The lifetime of a value is tied to the scope in which it is declared whereas the lifetime of
an object is not tied to the scope in which it is created, as demonstrated by the following
code:

{
int i = 42;
TextBox message = new TextBox();
} // i ends its life here,
// but the object referred to by TextBox lives on

 Values typically have very short lifetimes whereas objects typically have long lifetimes.

The Life and Times of an Object

 When we create an object, underneath, object creation is really a two-phase process.

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 34


Module 3 .Net framework for application development

 First we have to allocate some raw memory from the heap. We do this using the
new keyword. You have no control over this phase of an object's creation.
 Second we have to convert the raw memory into an object; have to initialize the object.
You do this by using a constructor. In contrast to allocation, you do have control over this
phase of an object's creation.
 Object death is also a two-phase process. The two phases exactly mirror the two phases
of creation.
 First we have to convert the object back into raw memory. We do this by writing a
destructor. The destructor is the opposite of the constructor.
 Second the raw memory has to be given back to the heap; the binary bits that the object
lived in have to be deallocated. Once again you have no control over this phase.
 The process of returning memory back to the heap is known as garbage collection.

Writing Destructors

 The syntax for writing a destructor is a tilde (~) followed by the name of the class. For
example, here's a simple class that counts the number of live instances by incrementing a
static count in the constructor and decrementing the static count in the destructor:
class Tally
{
public Tally()
{
instanceCount++;
}
~Tally()
{
instanceCount--;
}
public static int InstanceCount()
{
return instanceCount;

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 35


Module 3 .Net framework for application development

}
private static int instanceCount = 0;
}

There are some very important destructor restrictions:

 You cannot declare a destructor in a struct. A struct is a value type.

struct Tally
{
~Tally() { ... } // compile-time error
}

 You cannot declare an access modifier (such as public) for a destructor. This is because
you never call the destructor yourself (the garbage collector does, as you'll see shortly).

public ~Tally() { ... } // compile-time error

 You never declare a destructor with parameters. Again, this is because you never call the
destructor yourself.

~Tally(int parameter) { ... } // compile-time error

The compiler automatically translates a destructor into an override of


the Object.Finalize method. In other words, the compiler translates the following
destructor:

class Tally
{
~Tally() { ... }
}
Into this:
class Tally
{

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 36


Module 3 .Net framework for application development

protected override void Finalize()


{
try { ... }
finally { base.Finalize(); }
}
}

 The compiler-generated Finalize method contains the destructor body inside a try block,
followed by a finally block that calls the base class Finalize. This ensures that a
destructor always calls its base class destructor (just like in C++).
 It's important to realize that only the compiler can make this translation. You can't
override Finalize yourself and you can't call Finalize yourself. In other
words, Finalize really is just another name for the destructor.

Why Use the Garbage Collector?

The fundamental thing to remember about destructors is that we can never call them. The reason
for this is that, in C#, we can never destroy an object yourself. There just isn't any syntax to do it.
There are good reasons why the designers of C# decided to forbid the user from explicitly
writing code to destroy objects. If it was the user’s responsibility to destroy objects, sooner or
later:

 We could have forget to destroy the object. This would mean that the object's destructor
(if it had one) would not be run and its memory would not be deallocated back to the
heap. You'd quite easily run out of memory.
 We could try and destroy an active object. Remember, objects are held by reference. If a
class held a reference to a destroyed object, it would be a dangling reference. The
dangling reference would end up referring either to unused memory or to a completely
different object. Either way, the outcome of using such a dangling reference would be
undefined. All bets would be off.
 We could try and destroy the same object more than once.

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 37


Module 3 .Net framework for application development

These problems are unacceptable in a language like C#, which places robustness and security
high on its list of design goals. Instead, the garbage collector is responsible for destroying objects
Only the garbage collector can destroy objects. The garbage collector guarantees that:

 Each object is destroyed regardless of whether your application has explicitly destroyed
all the objects it created. For example, when a program ends, all the current objects will
be destroyed.
 Each object is destroyed only once.
 Each object is destroyed only when no other references refer to the object. This type of
object is called an unreachable object.

These guarantees are tremendously useful and free, the programmer, from tedious housekeeping
chores that are easy to get wrong. They allow you to concentrate on the logic of the program
itself and be more productive.

However, as with all design trade-offs, garbage collection comes at a price. We don't know the
order in which objects will be destroyed. Objects are not necessarily destroyed in the reverse
order that they are created in (as they are in C++). Neither do we know when the garbage
collector will decide to destroy objects. An object is not destroyed at the moment that it becomes
unreachable. Because destroying objects can be a time-consuming operation, the garbage
collector destroys objects only when it is necessary (when the heap memory is exhausted) or
when we explicitly ask it to (by calling the System.GC.Collect method). Clearly, this makes C#
unsuitable for some time-critical applications.

How Does the Garbage Collector Works?

The garbage collector runs in its own thread and only runs when other threads are in a safe state
(for example, when they are suspended). This is important because, as the garbage collector runs,
it needs to move objects and update object references. The steps that the garbage collector takes
when it runs are as follows:

1. It builds a graph of all reachable objects. It does this by repeatedly following reference
fields inside objects. The garbage collector builds this graph very carefully and makes

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 38


Module 3 .Net framework for application development

sure that circular references do not cause an infinite recursion. Any object not in this
graph must be unreachable.
2. It checks to see if any unreachable objects require finalization. In other words, it checks if
any of the unreachable objects has a destructor. Any unreachable object that requires
finalization is placed in a special queue called the freachable queue (pronounced F-
reachable).
3. The remaining unreachable objects (those that don't require finalization) are deallocated.
The garbage collector performs this deallocation by moving the reachable objects down
the heap, thus defragmenting the heap and freeing memory at the top of the heap. When
the garbage collector moves a reachable object, it also updates any references to the
object.
4. The garbage collector now allows other threads to resume.
5. The unreachable objects that require finalization (now in the freachable queue) are
finalized in a separate thread.

Note:

 Writing classes that contain destructors adds complexity to code and to the garbage
collection process and makes your program run more slowly. If your program does not
contain any destructors, the garbage collector does not need to perform Steps 3 and 5 (in
the previous section). Clearly, not doing something is faster than doing it. (There's no
code faster than no code.) The first recommendation is, therefore, to try to avoid using
destructors except when you really need them (for example, consider a using statement
instead; these are covered in the following section).
 If we write a destructor, need to write it very carefully. In particular, destructor calls other
objects, those other objects might have already had their destructor called by the garbage
collector (remember, the order of finalization is not guaranteed).
 Therefore its better to ensure that each destructor reclaims one resource and nothing else.
This can require splitting a class into two classes (one of which is the class dedicated to
managing the resource).

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 39


Module 3 .Net framework for application development

Resource Management

 Sometimes it's inadvisable to release a resource in a destructor; some resources are just
too valuable and too scarce to lie around unreleased for arbitrary lengths of time.
 Scarce resources need to be released, and they need to be released as soon as possible.
 In these situations, only option is to release the resource yourself.
 A disposal method is a method that disposes of a resource. If a class has a disposal
method, we can call it explicitly and thus control when the resource is released.

The Disposal Method Pattern

 An example of a class that contains a disposal method is the TextReader class from
the System.IO namespace.
 TextReader contains a virtual method called Close.
 The StreamReader (which reads characters from a stream) and StringReader (which
reads characters from a string) classes both derive from TextReader and both override
the Close method.
 Here's an example that reads lines from a file using the StreamReader class:
TextReader reader = new StreamReader(filename);
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
reader.Close();

 It's important to call Close when you have finished with reader to release the file handle
(and encoding) resources.
 However, there is a problem with this example; it's not exception-safe. If the call
toReadLine (or WriteLine) throws an exception, the call to Close will not happen; it will
be bypassed.

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 40


Module 3 .Net framework for application development

Exception-Safe Disposal

 One way to ensure that a disposal method is always called, regardless of whether there is
an exception, is to call the disposal method inside a finally block. Here's the previous
example using this technique:
TextReader reader = new StreamReader(filename);
try
{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
finally
{
reader.Close();
}

The using Statement

 The syntax for a using statement is as follows:


using ( type variable = initialization )
embeddedStatement

Such a using statement is precisely equivalent to the following translation:

{
type variable = initialization;
try
{
embeddedStatement

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 41


Module 3 .Net framework for application development

}
finally
{
if (variable != null)
{
//calls Dispose( ) method
((IDisposable)variable).Dispose();
}
}
}

 The variable you declare in a using statement must be of a type that implements
the IDisposable interface.
 The IDisposable interface lives in the System namespace and contains just one method
called Dispose:

namespace System
{
interface IDisposable
{
void Dispose();
}
}

 We can use a using statement as a clean, exception-safe, robust way to ensure that a
resource is always automatically released.
 The class containing the disposal method (for example, Close in TextReader) implements
the IDisposable interface (as TextReader does).
 The class implements Dispose (as it must) to call the disposal method (for
example, TextReader.Dispose calls TextReader.Close).

For example:

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 42


Module 3 .Net framework for application development

abstract class TextReader : IDisposable


{
public virtual void Dispose()
{
// calls Close
}
public virtual void Close()
{ }
}

Here is the best way to make sure that your code always calls Close on a TextReader:

using (TextReader reader = new StreamReader(filename))


{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}

Calling a Disposal Method from a Destructor

 One of the drawbacks of the disposal method pattern is that it relies on you (the
programmer) to call the disposal method, and programmers tend to occasionally forget to
do things like this.
 The trade-off in deciding whether to use destructors or disposal methods is this: A call to
a destructor will happen, just don't know when, whereas you know exactly when a call to
a disposal method happens, just can't be sure that it will actually happen because the user
might forget to call it. However, it is possible to ensure that a disposal method is always
called.

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 43


Module 3 .Net framework for application development

 The solution is to call the disposal method from a destructor. This acts as a useful
"backup." We might forget to call the disposal method, but atleast be sure that it will be
called, even if it's only when the program shuts down. An example of how to do this is:
class Example : IDisposable
{
private Resource scarce;
private bool disposed = false;
~Example()
{
Dispose();
}
public virtual void Dispose()
{
if (!disposed)
{
try {
// release scarce resource here
}
finally {
disposed = true;
GC.SuppressFinalize(this);
}
}
}
public void SomeBehavior()
{
checkIfDisposed();
}
private void checkIfDisposed()
{
if (disposed)

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 44


Module 3 .Net framework for application development

{
throw new ObjectDisposedException("Example");
}
}
}

Notice that:

 The class implements IDisposable.


 The Dispose method is public and can be called at any time.
 The Dispose method can be safely called multiple times.
 The destructor calls Dispose.
 The Dispose method calls GC.SuppressFinalize to stop the garbage collector from
needlessly calling the destructor. This is in fact optional; it might turn out that
calling GC.SuppressFinalize takes longer than letting the garbage collector call the
destructor.
 All the regular methods of the class check to see if the object has already been disposed.
If it has, they throw an exception.

Programs:

 Program illustrating Disposal Methods

using System;

class Car:IDisposable
{
string name;

public Car(string n)
{
name=n;
}

~Car()
{
Console.WriteLine("Within destructor of {0}", name);

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 45


Module 3 .Net framework for application development

public void Dispose()


{
Console.WriteLine("Within Dispose() of {0}", name);
GC.SuppressFinalize(this);
}
}

class Test
{
public static void Main()
{
Car c1=new Car("One");
Car c2=new Car("Two");
Car c3=new Car("Three");
Car c4=new Car("Four");
c1.Dispose();
c3.Dispose();
}
}

Output:

Within Dispose() of One


Within Dispose() of Three
Within destructor of Four
Within destructor of Two

 Program illustrating Destructors

using System;
class Test
{
public Test()
{}
~Test()
{
Console.WriteLine("Finalizing!!!");
}
public static void Main()
{
Console.WriteLine(“Within Main()");

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 46


Module 3 .Net framework for application development

Test t=new Test();


Console.WriteLine(“Exiting Main()");
}
}
Output:
Within Main()
Exiting Main()
Finalizing!!!

Mamatha A, Asst Prof, Dept of ISE,SVIT Page 47

You might also like