You are on page 1of 76

In this article we will discuss key concepts of object orientation with their practical

implementation in C#. We will discuss here basics of OOPS including Interfaces,


Access Modifiers, inheritance, polymorphism etc. This is my second article on csharp-
corner.com.

My first article was "Memory Management in .NET",


you can find this article at http://www.c-sharpcorner.com/
UploadFile/tkagarwal/
MemoryManagementInNet11232005064832AM/
MemoryManagementInNet.aspx

Key Concepts of Object Orientation

• Abstraction
• Encapsulation
• Polymorphism
• Inheritance.

Abstraction is the ability to generalize an object as a data type that has a specific
set of characteristics and is able to perform a set of actions.

Object-oriented languages provide abstraction via classes. Classes define the


properties and methods of an object type.

Examples:

• You can create an abstraction of a dog with characteristics, such as color,


height, and weight, and actions such as run and bite. The characteristics are
called properties, and the actions are called methods.
• A Recordset object is an abstract representation of a set of data.

Classes are blueprints for Object.


Objects are instance of classes.

C# Example of Class:

public class Draw


{
// Class code.
}

Object References

When we work with an object we are using a reference to that object. On the other
hand, when we are working with simple data types such as Integer, we are working
with the actual value rather than a reference.

When we create a new object using the New keyword, we store a reference to that
object in a variable. For instance:

Draw MyDraw = new Draw;


This code creates a new instance of Draw. We gain access to this new object via the
MyDraw variable. This variable holds a reference to the object.

Now we have a second variable, which also has a reference to that same object. We
can use either variable interchangeably, since they both reference the exact same
object. The thing we need to remember is that the variable we have is not the object
itself but, rather, is just a reference or pointer to the object itself.

Early binding means that our code directly interacts with the object, by directly
calling its methods. Since the compiler knows the object's data type ahead of time, it
can directly compile code to invoke the methods on the object. Early binding also
allows the IDE to use IntelliSense to aid our development efforts; it allows the
compiler to ensure that we are referencing methods that do exist and that we are
providing the proper parameter values.

Late binding means that our code interacts with an object dynamically at run-time.
This provides a great deal of flexibility since our code literally doesn't care what type
of object it is interacting with as long as the object supports the methods we want to
call. Because the type of the object isn't known by the IDE or compiler, neither
IntelliSense nor compile-time syntax checking is possible but we get unprecedented
flexibility in exchange.

If we enable strict type checking by using Option Strict On at the top of our code
modules, then the IDE and compiler will enforce early binding behavior. By default,
Option Strict is turned off and so we have easy access to the use of late binding
within our code.

Access Modifiers

Access Modifiers are keywords used to specify the declared accessibility of a member
of a type.

Public is visible to everyone. A public member can be accessed using an instance of


a class, by a class's internal code, and by any descendants of a class.

Private is hidden and usable only by the class itself. No code using a class instance
can access a private member directly and neither can a descendant class.
Protected members are similar to private ones in that they are accessible only by
the containing class. However, protected members also may be used by a
descendant class. So members that are likely to be needed by a descendant class
should be marked protected.

Internal/Friend is public to the entire application but private to any outside


applications. Internal is useful when you want to allow a class to be used by other
applications but reserve special functionality for the application that contains the
class. Internal is used by C# and Friend by VB .NET.

Protected Internal may be accessed only by a descendant class that's contained in


the same application as its base class. You use protected internal in situations where
you want to deny access to parts of a class functionality to any descendant classes
found in other applications.
Composition of an OBJECT

We use an interface to get access to an object's data and behavior. The object's data
and behaviors are contained within the object, so a client application can treat the
object like a black box accessible only through its interface. This is a key object-
oriented concept called Encapsulation. The idea is that any programs that make use
of this object won't have direct access to the behaviors or data-but rather those
programs must make use of our object's interface.

There are three main parts of Object:

1. Interface
2. Implementation or Behavior
3. Member or Instance variables

Interface

The interface is defined as a set of methods (Sub and Function routines), properties
(Property routines), events, and fields (variables or attributes) that are declared
Public in scope.

Implementation or Behavior

The code inside of a method is called the implementation. Sometimes it is also called
behavior since it is this code that actually makes the object do useful work.
Client applications can use our object even if we change the implementation-as long
as we don't change the interface. As long as our method name and its parameter list
and return data type remain unchanged, we can change the implementation all we
want.

So Method Signature depends on:

• Method name
• Data types of parameters
• Either Parameter is passed ByVal or ByRef.
• Return type of method.

It is important to keep in mind that encapsulation is a syntactic tool-it allows our


code to continue to run without change. However, it is not semantic-meaning that,
just because our code continues to run, doesn't mean it continues to do what we
actually wanted it to do.

Member or Instance Variables

The third key part of an object is its data, or state. Every instance of a class is
absolutely identical in terms of its interface and its implementation-the only thing
that can vary at all is the data contained within that particular object.

Member variables are those declared so that they are available to all code within our
class. Typically member variables are Private in scope-available only to the code in
our class itself. They are also sometimes referred to as instance variables or as
attributes. The .NET Framework also refers to them as fields.
We shouldn't confuse instance variables with properties. A Property is a type of
method that is geared around retrieving and setting values, while an instance
variable is a variable within the class that may hold the value exposed by a Property.

Interface looks like a class, but has no implementation.

The only thing it contains is definitions of events, indexers, methods and/or


properties. The reason interfaces only provide definitions is because they are
inherited by classes and structs, which must provide an implementation for each
interface member defined. So, what are interfaces good for if they don't implement
functionality? They're great for putting together plug-n-play like architectures where
components can be interchanged at will. Since all interchangeable components
implement the same interface, they can be used without any extra programming.
The interface forces each component to expose specific public members that will be
used in a certain way.

Because interfaces must be defined by inheriting classes and structs, they define a
contract. For instance, if class foo inherits from the IDisposable interface, it is
making a statement that it guarantees it has the Dispose() method, which is the only
member of the IDisposable interface. Any code that wishes to use class foo may
check to see if class foo inherits IDisposable. When the answer is true, then the code
knows that it can call foo.Dispose().

Defining an Interface: MyInterface.c

interface IMyInterface
{
void MethodToImplement();
}

Above listing shows defines an interface named IMyInterface. A common naming


convention is to prefix all interface names with a capital "I", but this is not
mandatory. This interface has a single method named MethodToImplement(). This
could have been any type of method declaration with different parameters and return
types. Notice that this method does not have an implementation (instructions
between curly braces- {}), but instead ends with a semi-colon, ";". This is because
the interface only specifies the signature of methods that an inheriting class or struct
must implement.

All the methods of Interface are public by default and no access modifiers (like
private, public) are allowed with any method of Interface.

Using an Interface: InterfaceImplementer.cs

class InterfaceImplementer : IMyInterface


{
public void MethodToImplement()
{
Console.WriteLine("MethodToImplement() called.");
}
}

The InterfaceImplementer class in above listing implements the IMyInterface


interface. Indicating that a class inherits an interface is the same as inheriting a
class. In this case, the following syntax is used:

class InterfaceImplementer : IMyInterface

Note that this class inherits the IMyInterface interface; it must implement its all
members. While implementing interface methods all those needs to be declared
public only. It does this by implementing the MethodToImplement() method. Notice
that this method implementation has the exact same signature, parameters and
method name, as defined in the IMyInterface interface. Any difference will cause a
compiler error. Interfaces may also inherit other interfaces. Following listing shows
how inherited interfaces are implemented.

Interface Inheritance: InterfaceInheritance.cs

using System;
interface IParentInterface
{
void ParentInterfaceMethod();
}
interface IMyInterface : IParentInterface
{
void MethodToImplement();
}
class InterfaceImplementer : IMyInterface
{
public void MethodToImplement()
{
Console.WriteLine("MethodToImplement() called.");
}
public void ParentInterfaceMethod()
{
Console.WriteLine("ParentInterfaceMethod() called.");
}
}

The code in above listing contains two interfaces: IMyInterface and the interface it
inherits, IParentInterface. When one interface inherits another, any implementing
class or struct must implement every interface member in the entire inheritance
chain. Since the InterfaceImplementer class in above listing inherits from
IMyInterface, it also inherits IParentInterface. Therefore, the InterfaceImplementer
class must implement the MethodToImplement() method specified in the
IMyInterface interface and the ParentInterfaceMethod() method specified in the
IParentInterface interface.

In summary, you can implement an interface and use it in a class. Interfaces may
also be inherited by other interface. Any class or struct that inherits an interface
must also implement all members in the entire interface inheritance chain.

Inheritance is the idea that one class, called a subclass, can be based on another
class, called a base class. Inheritance provides a mechanism for creating hierarchies
of objects.

Inheritance is the ability to apply another class's interface and code to your own
class.

Normal base classes may be instantiated themselves, or inherited. Derived classes


can inherit base class members marked with protected or greater access. The
derived class is specialized to provide more functionality, in addition to what its base
class provides. Inheriting base class members in derived class is not mandatory.

Access Keywords

base -> Access the members of the base class.


this -> Refer to the current object for which a method is called.

The base keyword is used to access members of the base class from within a derived
class:
Call a method on the base class that has been overridden by another method.
Specify which base-class constructor should be called when creating instances of the
derived class. A base class access is permitted only in a constructor, an instance
method, or an instance property accessor.

In following example, both the base class, Person, and the derived class, Employee,
have a method named Getinfo. By using the base keyword, it is possible to call the
Getinfo method on the base class, from within the derived class.

// Accessing base class members

using System;
public class Person
{
protected string ssn = "444-55-6666";
protected string name = "John L. Malgraine";
public virtual void GetInfo()
{
Console.WriteLine("Name: {0}", name);
Console.WriteLine("SSN: {0}", ssn);
}
}
class Employee: Person
{
public string id = "ABC567EFG";
public override void GetInfo()
{
// Calling the base class GetInfo method:
base.GetInfo();
Console.WriteLine("Employee ID: {0}", id);
}
}
class TestClass
{
public static void Main()
{
Employee E = new Employee();
E.GetInfo();
}
}

Output
Name: John L. Malgraine
SSN: 444-55-6666
Employee ID: ABC567EFG

Base class constructors can be called from derived classes. To call a base class
constructor, use the base() constructor reference. This is desirable when it's
necessary to initialize a base class appropriately.

Here's an example that shows the derived class constructor with an address
parameter:

abstract public class Contact


{
private string address;
public Contact(string b_address)
{
this.address = b_address;
}
}
public class Customer : Contact
{
public Customer(string c_address) : base(C_address)
{
}
}

In this code, the Customer class does not have an address, so it passes the
parameter to its base class constructor by adding a colon and the base keyword with
the parameter to its declaration. This calls the Contact constructor with the address
parameter, where the address field in Contact is initialized.

One more example which shows how base-class constructor is called when creating
instances of a derived class:

using System;
public class MyBase
{
int num;
public MyBase()
{
Console.WriteLine("In MyBase()");
}
public MyBase(int i)
{
num = i;
Console.WriteLine("in MyBase(int i)");
}
public int GetNum()
{
return num;
}
}
public class MyDerived : MyBase
{
static int i = 32;
// This constructor will call MyBase.MyBase()
public MyDerived(int ii) : base()
{
}
// This constructor will call MyBase.MyBase(int i)
public MyDerived() : base(i)
{
}
public static void Main()
{
MyDerived md = new MyDerived(); // calls public MyDerived() : base(i) and
// passes i=32 in base class
MyDerived md1 = new MyDerived(1); // call public MyDerived() : base(i)
}
}

Output
in MyBase(int i)
in MyBase()

The following example will not compile. It illustrates the effects of not including a
default constructor in a class definition:

abstract public class Contact


{
private string address;
public Contact(string address)
{
this.address = address;
}
}
public class Customer : Contact
{
public Customer(string address)
{
}
}

In this example, the Customer constructor does not call the base class constructor.
This is obviously a bug, since the address field will never be initialized.

When a class has no explicit constructor, the system assigns a default constructor.
The default constructor automatically calls a default or parameterless base
constructor. Here's an example of automatic default constructor generation that
would occur for the preceding example:

public Customer() : Contact()


{
}

When a class does not declare any constructors, the code in this example is
automatically generated. The default base class constructor is called implicitly when
no derived class constructors are defined. Once a derived class constructor is
defined, whether or not it has parameters, a default constructor will not be
automatically defined, as the preceding code showed.

Calling Base Class Members

Derived classes can access the members of their base class if those members have
protected or greater access. Simply use the member name in the appropriate
context, just as if that member were a part of the derived class itself. Here's an
example:

abstract public class Contact


{
private string address;
private string city;
private string state;
private string zip;
public string FullAddress()
{
string fullAddress = address + '\n' + city + ',' + state + ' ' + zip;
return fullAddress;
}
}
public class Customer : Contact
{
public string GenerateReport()
{
string fullAddress = FullAddress();
// do some other stuff...
return fullAddress;
}
}

In above example, the GenerateReport() method of the Customer class calls the
FullAddress() method in its base class, Contact. All classes have full access to their
own members without qualification. Qualification refers to using a class name with
the dot operator to access a class member-MyObject.SomeMethod(), for instance.
This shows that a derived class can access its base class members in the same
manner as its own.

More Tips regarding Inheritance:

• A static member cannot be marked as override, virtual, or abstract. So


following is an error:
public static virtual void GetSSN()
• You can't call static methods of base class from derived class using base
keyword.
In above example if you declare a static method as follows:

public class Person


{
protected string ssn = "444-55-6666";
protected string name = "John L. Malgraine";
public static void GetInfo()
{
// Implementation
}
}

now you can't call this method using base.GetInfo() from derived class instead you
have to call Person.GetInfo() from derived class.

Inside Static members we can access only static fields, methods etc.
Following example will give error, because we can't access name in GetInfo()
because name is not static.

public class Person


{
protected string ssn = "444-55-6666";
protected string name = "John L. Malgraine";
public static void GetInfo()
{
Console.WriteLine("Name: {0}", name);
Console.WriteLine("SSN: {0}", ssn);
}
}

Virtual or abstract members cannot be private.


• If you are not overriding a virtual method of base class in derived class, you
can't use base class method by using base keyword in derived class. Also
when you will create an instance of derived class, it will call derived class
method and you will only be able to access base class method when you will
create instance of base class.
• You can't decrease access level of a method in derived class when you are
overriding a base class method in derived class, vice versa is possible.
Means you can make protected method of base class to public in derived
class.

The "this" keyword refers to:

• the current instance for which a method is called. Static member functions do
not have a this pointer. The this keyword can be used to access members
from within constructors, instance methods, and instance accessors.
The following are common uses of this:

To qualify members hidden by similar names, for example:

public Employee(string name, string alias)


{
this.name = name;
this.alias = alias;
}

In above example, this.name refers to private variable name in the class. If we write
name = name, then this will refer to argument name of the constructor Employee
and not to private variable name in the class. In this case private variable name will
never be initialized.

• To pass an object as a parameter to other methods, for example:


CalcTax(this);

To declare indexers, for example:

public int this [int param]


{
get
{
return array[param];
}
set
{
array[param] = value;
}
}

It is an error to refer to this in a static method, static property accessor, or variable


initializer of a field declaration.
In this example, this is used to qualify the Employee class members, name and alias,
which are hidden by similar names. It is also used to pass an object to the method
CalcTax, which belongs to another class.

// keywords_this.cs
// this example
using System;
public class Employee
{
public string name;
public string alias;
public decimal salary = 3000.00m;
// Constructor:
public Employee(string name, string alias)
{
// Use this to qualify the fields, name and alias:
this.name = name;
this.alias = alias;
}
// Printing method:
public void printEmployee()
{
Console.WriteLine("Name: {0}\nAlias: {1}", name, alias);
// Passing the object to the CalcTax method by using this:
Console.WriteLine("Taxes: {0:C}", Tax.CalcTax(this));
}
}
public class Tax
{
public static decimal CalcTax(Employee E)
{
return (0.08m*(E.salary));
}
}
public class MainClass
{
public static void Main()
{
// Create objects:
Employee E1 = new Employee ("John M. Trainer", "jtrainer");
// Display results:
E1.printEmployee();
}
}

Output
Name: John M. Trainer
Alias: jtrainer
Taxes: $240.00

Abstract Classes
Abstract classes are a special type of base classes. In addition to normal class
members, they have abstract class members. These Abstract class members are
methods and properties that are declared without an implementation. All classes
derived directly from abstract classes must implement all of these abstract methods
and properties.

Abstract classes can never be instantiated. This would be illogical, because of the
members without implementations.So what good is a class that can't be
instantiated? Lots! Abstract classes sit toward the top of a class hierarchy. They
establish structure and meaning to code. They make frameworks easier to build. This
is possible because abstract classes have information and behavior common to all
derived classes in a framework. Take a look at the following example:

abstract public class Contact // Abstract Class Contact.


{
protected string name;
public Contact()
{
// statements...
}
public abstract void generateReport();
abstract public string Name
{
get;
set;
}
}

Contact, is an abstract class. Contact has two abstract members, and it has an
abstract method named generateReport(). This method is declared with the abstract
modifier in front of the method declaration. It has no implementation (no braces)
and is terminated with a semicolon. The Name property is also declared abstract.
The accessors of properties are terminated with semicolons.

public class Customer : Contact // Customer Inherits Abstract Class Contact.


{
string gender;
decimal income;
int numberOfVisits;
public Customer()
{
// statements
}
public override void generateReport()
{
// unique report
}
public override string Name
{
get
{
numberOfVisits++;
return name;
}
set
{
name = value;
numberOfVisits = 0;
}
}
}
public class SiteOwner : Contact
{
int siteHits;
string mySite;
public SiteOwner()
{
// statements
}
public override void generateReport()
{
// unique report
}
public override string Name
{
get
{
siteHits++;
return name;
}
set
{
name = value;
siteHits = 0;
}
}
}

The abstract base class Contact has two derived classes, Customer and SiteOwner.
Both of these derived classes implement the abstract members of the Contact class.
The generateReport() method in each derived class has an override modifier in its
declaration. Likewise, the Name declaration contains an override modifier in both
Customer and SiteOwner.

C# requires explicit declaration of intent when overriding methods. This feature


promotes safe code by avoiding the accidental overriding of base class methods,
which is what actually does happen in other languages. Leaving out the override
modifier generates an error. Similarly, adding a new modifier also generates an
error. Abstract methods must be overridden and cannot be hidden, which the new
modifier or the lack of a modifier would be trying to do.

The most famous of all abstract classes is the Object class. It may be referred to as
object or Object, but it's still the same class. Object is the base class for all other
classes in C#. It's also the default base class when a base class is not specified. The
following class declarations produce the same exact results:
abstract public class Contact : Object
{
// class members
}
abstract public class Contact
{
// class members
}

Object is implicitly included as a base class if it is not already declared. Besides


providing the abstract glue to hold together the C# class framework, object includes
built-in functionality, some of which is useful for derived classes to implement.

Difference between Interface and Abstract Class

• Interfaces are closely related to abstract classes that have all members
abstract.
• For an abstract class, at least one method of the class must be an abstract
method that means it may have concrete methods.
• For an interface, all the methods must be abstract
• Class that implements an interface much provide concrete implementation of
all the methods definition in an interface or else must be declare an abstract
class
• In C#, multiple inheritance is possible only through implementation of
multiple interfaces. Abstract class can only be derived once.
• An interface defines a contract and can only contains four entities viz
methods, properties, events and indexes. An interface thus cannot contain
constants, fields, operators, constructors, destructors, static constructors, or
types.
• Also an interface cannot contain static members of any kind. The modifiers
abstract, public, protected, internal, private, virtual, override is disallowed, as
they make no sense in this context.
• Class members that implement the interface members must be publicly
accessible.

Overriding Summery:

A derived class may override a virtual method of the base class with the keyword
override. The following restrictions must be followed.

• Keyword override is used in the definition of child class method that is going
to override the base class's virtual method.
• The return type must be the same as the virtual method have in base class.
• The name of the method should also be same.
• The parameter-list must also be same in order, number and type of
parameters.
• The accessibility of the overriding method should not be more restricted than
that of the accessibility defined with virtual method of the base class. This
accessibility either be the same or less restricted.
• The virtual methods can be sealed in the child or derived classes to prevent
further modifications in the implementation of the virtual method in the
derived classes, by declaring them as sealed methods.

Hiding Base Class Members

Sometimes derived class members have the same name as a corresponding base
class member. In this case, the derived member is said to be "hiding" the base class
member.

When hiding occurs, the derived member is masking the functionality of the base
class member. Users of the derived class won't be able to see the hidden member;
they'll see only the derived class member. The following code shows how hiding a
base class member works.

abstract public class Contact


{
private string address;
private string city;
private string state;
private string zip;
public string FullAddress()
{
string fullAddress =address + '\n' +city + ',' + state + ' ' + zip;
return fullAddress;
}
}
public class SiteOwner : Contact
{
public string FullAddress()
{
string fullAddress;
// create an address...
return fullAddress;
}
}

In this example, both SiteOwner and its base class, Contact, have a method named
FullAddress(). The FullAddress() method in the SiteOwner class hides the
FullAddress() method in the Contact class. This means that when an instance of a
SiteOwner class is invoked with a call to the FullAddress() method, it is the
SiteOwner class FullAddress() method that is called, not the FullAddress() method of
the Contact class.

Although a base class member may be hidden, the derived class can still access it. It
does this through the base identifier. Sometimes this is desirable. It is often useful to
take advantage of the base class functionality and then add to it with the derived
class code. The next example shows how to refer to a base class method from the
derived class.

abstract public class Contact


{
private string address;
private string city;
private string state;
private string zip;
public string FullAddress()
{
string fullAddress =address + '\n' +city + ',' + state + ' ' + zip;
return fullAddress;
}
}
public class SiteOwner : Contact
{
public string FullAddress()
{
string fullAddress = base.FullAddress();
// do some other stuff...
return fullAddress;
}
}

In this particular example, the FullAddress() method of the Contact class is called
from within the FullAddress() method of the SiteOwner class. This is accomplished
with a base class reference. This provides another way to reuse code and add on to it
with customized behavior.

Versioning

Versioning, in the context of inheritance, is a C# mechanism that allows modification


of classes (creating new versions) without accidentally changing the meaning of the
code. Hiding a base class member with the methods previously described generates
a warning message from the compiler. This is because of the C# versioning policy.
It's designed to eliminate a class of problems associated with modifications to base
classes.

Here's the scenario: A developer creates a class that inherits from a third-party
library. For the purposes of this discussion, we assume that the Contact class
represents the third-party library. Here's the example:

public class Contact


{
// does not include FullAddress() method
}
public class SiteOwner : Contact
{
public string FullAddress()
{
string fullAddress = mySite.ToString();
return fullAddress;
}
}

In this example, the FullAddress() method does not exist in the base class. There is
no problem yet. Later on, the creators of the third-party library update their code.
Part of this update includes a new member in a base class with the exact same name
as the derived class:

public class Contact


{
private string address;
private string city;
private string state;
private string zip;
public string FullAddress()
{
string fullAddress =address + '\n' +city + ',' + state + ' ' + zip;
return fullAddress;
}
}
public class SiteOwner : Contact
{
public string FullAddress()
{
string fullAddress = mySite.ToString();
return fullAddress;
}
}

In this code, the base class method FullAddress() contains different functionality
than the derived class method. In other languages, this scenario would break the
code because of implicit polymorphism. However, this does not break any code in C#
because when the FullAddress() method is called on SiteOwner, it is still the
SiteOwner class method that gets called.

This scenario generates a warning message. One way to eliminate the warning
message is to place a new modifier in front of the derived class method name, as the
following example shows:

using System;
public class WebSite
{
public string SiteName;
public string URL;
public string Description;
public WebSite()
{
}
public WebSite( string strSiteName, string strURL, string strDescription )
{
SiteName = strSiteName;
URL = strURL;
Description = strDescription;
}
public override string ToString()
{
return SiteName + ", " +URL + ", " +Description;
}
}
public class Contact
{
public string address;
public string city;
public string state;
public string zip;
public string FullAddress()
{
string fullAddress =address + '\n' +city + ',' + state + ' ' + zip;
return fullAddress;
}
}
public class SiteOwner : Contact
{
int siteHits;
string name;
WebSite mySite;
public SiteOwner()
{
mySite = new WebSite();
siteHits = 0;
}
public SiteOwner(string aName, WebSite aSite)
{
mySite = new WebSite(aSite.SiteName,aSite.URL,aSite.Description);
Name = aName;
}
new public string FullAddress()
{
string fullAddress = mySite.ToString();
return fullAddress;
}
public string Name
{
get
{
siteHits++;
return name;
}
set
{
name = value;
siteHits = 0;
}
}
}
public class Test
{
public static void Main()
{
WebSite mySite = new WebSite("Le Financier","http://www.LeFinancier.com","Fancy
Financial Site");
SiteOwner anOwner = new SiteOwner("John Doe", mySite);
string address;
anOwner.address = "123 Lane Lane";
anOwner.city = "Some Town";
anOwner.state = "HI";
anOwner.zip = "45678";
address = anOwner.FullAddress(); // Different Results
Console.WriteLine("Address: \n{0}\n", address);
}
}

Here's the output:


Address:
Le Financier, http://www.LeFinancier.com, Fancy Financial Site

This has the effect of explicitly letting the compiler know the developer's intent.
Placing the new modifier in front of the derived class member states that the
developers know there is a base class method with the same name, and they
definitely want to hide that member. This prevents breakage of existing code that
depends on the implementation of the derived class member. With C#, the method
in the derived class is called when an object of the derived class type is used.
Likewise, the method in the base class is called when an object of the Base class
type is called. Another problem this presents is that the base class may present
some desirable new features that wouldn't be available through the derived class.

To use these new features requires one of a few different workarounds. One option
would be to rename the derived class member, which would allow programs to use a
base class method through a derived class member. The drawback to this option
would be if there were other classes relying upon the implementation of the derived
class member with the same name. This scenario will break code and, for this
reason, is considered extremely bad form.

Another option is to define a new method in the derived class that called the base
class method. This allows users of the derived class to have the new functionality of
the base class, yet retain their existing functionality with the derived class. While this
would work, there are maintainability concerns for the derived class.

Sealed Classes

Sealed classes are classes that can't be derived from. To prevent other classes from
inheriting from a class, make it a sealed class. There are a couple good reasons to
create sealed classes, including optimization and security.

Sealing a class avoids the system overhead associated with virtual methods. This
allows the compiler to perform certain optimizations that are otherwise unavailable
with normal classes.

Another good reason to seal a class is for security. Inheritance, by its very nature,
dictates a certain amount of protected access to the internals of a potential base
class. Sealing a class does away with the possibility of corruption by derived classes.
A good example of a sealed class is the String class. The following example shows
how to create a sealed class:

public sealed class CustomerStats


{
string gender;
decimal income;
int numberOfVisits;
public CustomerStats()
{
}
}
public class CustomerInfo : CustomerStats // error
{
}

This example generates a compiler error. Since the CustomerStats class is sealed, it
can't be inherited by the CustomerInfo class.The CustomerStats class was meant to
be used as an encapsulated object in another class. This is shown by the declaration
of a CustomerStats object in the Customer class.

public class Customer


{
CustomerStats myStats; // okay
}

Polymorphism

Polymorphism is reflected in the ability to write one routine that can operate on
objects from more than one class-treating different objects from different classes in
exactly the same way. For instance, if both Customer and Vendor objects have a
Name property, and we can write a routine that calls the Name property regardless
of whether we're using a Customer or Vendor object, then we have polymorphism.

A vehicle is a good example of polymorphism. A vehicle interface would only have


those properties and methods that all vehicles have, a few of which might include
paint color, number of doors, accelerator, and ignition. These properties and
methods would apply to all types of vehicles including cars, trucks, and semi-trucks.

Polymorphism will not implement code behind the vehicle's properties and methods.
Instead, polymorphism is the implementation of an interface. If the car, truck, and
semitruck all implement the same vehicle interface, then the client code for all three
classes can be exactly the same.

C# gives us polymorphism through inheritance. C# provides a keyword virtual that is


used in the definition of a method to support polymorphism.

Child class are now free to provide their own implementation of this virtual method,
that is called overriding. The following points are important regarding virtual
keyword:-
If the method is not virtual, the compiler simply uses the reference type to invoke
the appropriate method.

If the method is virtual, the compiler will generate code to checkup the reference
type at runtime it is actually denoting to, then the appropriate method is called from
the class of the reference type.

When a virtual method is called, runtime check (late method binding) is made to
identify the object and appropriate method is invoked, all this is done at runtime.

In case of non-virtual methods, this information is available at compile time, so no


runtime check to identify the object is made, so slightly efficient in the way non-
virtual methods are called. But the behavior of virtual method is useful in many
ways; the functionality they provide is fair enough to bear this slight loss of
performance.

Implementing Polymorphism

The key factor here is the ability to dynamically invoke methods in a class based on
their type. Essentially, a program would have a group of objects, examine the type
of each one, and execute the appropriate method. Here's an example:

using System;
public class WebSite
{
public string SiteName;
public string URL;
public string Description;
public WebSite()
{
}
public WebSite( string strSiteName, string strURL, string strDescription )
{
SiteName = strSiteName;
URL = strURL;
Description = strDescription;
}
public override string ToString()
{
return SiteName + ", " +URL + ", " +Description;
}
}

When we inherit above class, we have two choices to invoke constructor of the class.
So this is an example of design time polymorphism. Here at design time we have to
decide which method we need to invoke while inheriting the class.

Polymorphism is the capability of a program to carry out dynamic operations by


implementing methods of multiple derived classes through a common base class
reference. Another definition of polymorphism is the ability to treat different objects
the same way. This means that the runtime type of an object determines its
behavior rather than the compile-time type of its reference
Resource Allocation

The Microsoft .NET common language runtime requires that all resources be
allocated from the managed heap. Objects are automatically freed when they are no
longer needed by the application.

When a process is initialized, the runtime reserves a contiguous region of address


space that initially has no storage allocated for it. This address space region is the
managed heap. The heap also maintains a pointer. This pointer indicates where the
next object is to be allocated within the heap. Initially, the pointer is set to the base
address of the reserved address space region.

An application creates an object using the new operator. This operator first makes
sure that the bytes required by the new object fit in the reserved region (committing
storage if necessary). If the object fits, then pointer points to the object in the heap,
this object's constructor is called, and the new operator returns the address of the
object.

Above fig shows a managed heap consisting of three objects: A, B, and C. The next
object to be allocated will be placed where NextObjPtr points (immediately after
object C).

When an application calls the new operator to create an object, there may not be
enough address space left in the region to allocate to the object. The heap detects
this by adding the size of the new object to NextObjPtr. If NextObjPtr is beyond the
end of the address space region, then the heap is full and a collection must be
performed.

In reality, a collection occurs when generation 0 is completely full. Briefly, a


generation is a mechanism implemented by the garbage collector in order to improve
performance. The idea is that newly created objects are part of a young generation,
and objects created early in the application's lifecycle are in an old generation.
Separating objects into generations can allow the garbage collector to collect specific
generations instead of collecting all objects in the managed heap.

The Garbage Collection Algorithm


The garbage collector checks to see if there are any objects in the heap that are no
longer being used by the application. If such objects exist, then the memory used by
these objects can be reclaimed. (If no more memory is available for the heap, then
the new operator throws an OutOfMemoryException.)

Every application has a set of roots. Roots identify storage locations, which refer to
objects on the managed heap or to objects that are set to null. For example, all the
global and static object pointers in an application are considered part of the
application's roots. In addition, any local variable/parameter object pointers on a
thread's stack are considered part of the application's roots. Finally, any CPU
registers containing pointers to objects in the managed heap are also considered part
of the application's roots. The list of active roots is maintained by the just-in-time
(JIT) compiler and common language runtime, and is made accessible to the garbage
collector's algorithm.

When the garbage collector starts running, it makes the assumption that all objects
in the heap are garbage. In other words, it assumes that none of the application's
roots refer to any objects in the heap. Now, the garbage collector starts walking the
roots and building a graph of all objects reachable from the roots. For example, the
garbage collector may locate a global variable that points to an object in the heap.

Following fig shows a heap with several allocated objects where the application's
roots refer directly to objects A, C, D, and F. All of these objects become part of the
graph. When adding object D, the collector notices that this object refers to object H,
and object H is also added to the graph. The collector continues to walk through all
reachable objects recursively.

Once this part of the graph is complete, the garbage collector checks the next root
and walks the objects again. As the garbage collector walks from object to object, if
it attempts to add an object to the graph that it previously added, then the garbage
collector can stop walking down that path. This serves two purposes. First, it helps
performance significantly since it doesn't walk through a set of objects more than
once. Second, it prevents infinite loops should you have any circular linked lists of
objects.

Once all the roots have been checked, the garbage collector's graph contains the set
of all objects that are somehow reachable from the application's roots; any objects
that are not in the graph are not accessible by the application, and are therefore
considered garbage.

The garbage collector now walks through the heap linearly, looking for contiguous
blocks of garbage objects (now considered free space). The garbage collector then
shifts the non-garbage objects down in memory (using the standard memcpy
function), removing all of the gaps in the heap. Of course, moving the objects in
memory invalidates all pointers to the objects. So the garbage collector must modify
the application's roots so that the pointers point to the objects' new locations. In
addition, if any object contains a pointer to another object, the garbage collector is
responsible for correcting these pointers as well.

Following fig shows the managed heap after a collection.


After all the garbage has been identified, all the non-garbage has been compacted,
and all the non-garbage pointers have been fixed-up, the NextObjPtr is positioned
just after the last non-garbage object. At this point, the new operation is tried again
and the resource requested by the application is successfully created.

GC generates a significant performance hit, and this is the major downside of using a
managed heap. However, keep in mind that GCs only occur when the heap is full
and, until then, the managed heap is significantly faster than a C-runtime heap. The
runtime's garbage collector also offers some optimizations using Generations that
greatly improve the performance of garbage collection.

You no longer have to implement any code that manages the lifetime of any
resources that your application uses. Now it is not possible to leak resources, since
any resource not accessible from your application's roots can be collected at some
point. Also it is not possible to access a resource that is freed, since the resource
won't be freed if it is reachable. If it's not reachable, then your application has no
way to access it.

Following code demonstrates how resources are allocated and managed:

class Application
{
public static int Main(String[] args)
{
// ArrayList object created in heap, myArray is now in root
ArrayList myArray = new ArrayList();
// Create 10000 objects in the heap
for (int x = 0; x < 10000; x++)
{
myArray.Add(new Object()); // Object object created in heap
}
// Right now, myArray is a root (on the thread's stack). So,
// myArray is reachable and the 10000 objects it points to are also reachable.
Console.WriteLine(myArray.Count);
// After the last reference to myArray in the code, myArray is not a root.
// Note that the method doesn't have to return, the JIT compiler knows
// to make myArray not a root after the last reference to it in the code.
// Since myArray is not a root, all 10001 objects are not reachable
// and are considered garbage. However, the objects are not
// collected until a GC is performed.
}
}

If GC is so great, you might be wondering why it isn't in ANSI C++. The reason is
that a garbage collector must be able to identify an application's roots and must also
be able to find all object pointers. The problem with C++ is that it allows casting a
pointer from one type to another, and there's no way to know what a pointer refers
to. In the common language runtime, the managed heap always knows the actual
type of an object, and the metadata information is used to determine which
members of an object refer to other objects.

Generations

One feature of the garbage collector that exists purely to improve performance is
called generations. A generational garbage collector (also known as an ephemeral
garbage collector) makes the following assumptions:

• The newer an object is, the shorter its lifetime will be.
• The older an object is, the longer its lifetime will be.
• Newer objects tend to have strong relationships to each other and are
frequently accessed around the same time.
• Compacting a portion of the heap is faster than compacting the whole heap.

When initialized, the managed heap contains no objects. Objects added to the heap
are said to be in generation 0, as you can see in following fig. Stated simply, objects
in generation 0 are young objects that have never been examined by the garbage
collector.
Now, if more objects are added to the heap, the heap fills and a garbage collection
must occur. When the garbage collector analyzes the heap, it builds the graph of
garbage (shown here in Green) and non-garbage objects. Any objects that survive
the collection are compacted into the left-most portion of the heap. These objects
have survived a collection, are older, and are now considered to be in generation 1.
As even more objects are added to the heap, these new, young objects are placed in
generation 0. If generation 0 fills again, a GC is performed. This time, all objects in
generation 1 that survive are compacted and considered to be in generation 2 (see
following fig). All survivors in generation 0 are now compacted and considered to be
in generation 1. Generation 0 currently contains no objects, but all new objects will
go into generation 0.
Currently, generation 2 is the highest generation supported by the runtime's garbage
collector. When future collections occur, any surviving objects currently in generation
2 simply stay in generation 2.

Generational GC Performance Optimizations

Generational garbage collecting improves performance. When the heap fills and a
collection occurs, the garbage collector can choose to examine only the objects in
generation 0 and ignore the objects in any greater generations. After all, the newer
an object is, the shorter its lifetime is expected to be. So, collecting and compacting
generation 0 objects is likely to reclaim a significant amount of space from the heap
and be faster than if the collector had examined the objects in all generations.

A generational collector can offer more optimizations by not traversing every object
in the managed heap. If a root or object refers to an object in an old generation, the
garbage collector can ignore any of the older objects' inner references, decreasing
the time required to build the graph of reachable objects. Of course, it is possible
that an old object refers to a new object. So that these objects are examined, the
collector can take advantage of the system's write-watch support (provided by the
Win32 GetWriteWatch function in Kernel32.dll). This support lets the collector know
which old objects (if any) have been written to since the last collection. These
specific old objects can have their references checked to see if they refer to any new
objects.
If collecting generation 0 doesn't provide the necessary amount of storage, then the
collector can attempt to collect the objects from generations 1 and 0. If all else fails,
then the collector can collect the objects from all generations-2, 1, and 0.

One of the assumptions stated earlier was that newer objects tend to have strong
relationships to each other and are frequently accessed around the same time. Since
new objects are allocated contiguously in memory, you gain performance from
locality of reference. More specifically, it is highly likely that all the objects can reside
in the CPU's cache. Your application will access these objects with phenomenal speed
since the CPU will be able to perform most of its manipulations without having cache
misses which forces RAM access.

Microsoft's performance tests show that managed heap allocations are faster than
standard allocations performed by the Win32 HeapAlloc function. These tests also
show that it takes less than 1 millisecond on a 200 MHz Pentium to perform a full GC
of generation 0. It is Microsoft's goal to make GCs take no more time than an
ordinary page fault.

Disadvantages of Win32 heap:

• Most heaps (like the C runtime heap) allocate objects wherever they find free
space. Therefore, if I create several objects consecutively, it is quite possible
that these objects will be separated by megabytes of address space.
However, in the managed heap, allocating several objects consecutively
ensures that the objects are contiguous in memory.
• When memory is allocated from a Win32 heap, the heap must be examined to
find a block of memory that can satisfy the request. This is not required in
managed heap, since here objects are contiguous in memory.
• In Win32 heap, data structures that the heap maintains must be updated. The
managed heap, on the other hand, only needs to increment the heap pointer.

Finalization

The garbage collector offers an additional feature that you may want to take
advantage of: finalization. Finalization allows a resource to gracefully clean up after
itself when it is being collected. By using finalization, a resource representing a file or
network connection is able to clean itself up properly when the garbage collector
decides to free the resource's memory.

When the garbage collector detects that an object is garbage, the garbage collector
calls the object's Finalize method (if it exists) and then the object's memory is
reclaimed. For example, let's say you have the following type (in C#):

public class BaseObj


{
public BaseObj()
{
}
protected override void Finalize()
{
// Perform resource cleanup code here
// Example: Close file/Close network connection
Console.WriteLine("In Finalize.");
}
}

Now you can create an instance of this object by calling:

BaseObj bo = new BaseObj();

Some time in the future, the garbage collector will determine that this object is
garbage. When that happens, the garbage collector will see that the type has a
Finalize method and will call the method, causing "In Finalize" to appear in the
console window and reclaiming the memory block used by this object.

Many developers who are used to programming in C++ draw an immediate


correlation between a destructor and the Finalize method. However, object
finalization and destructors have very different semantics and it is best to forget
everything you know about destructors when thinking about finalization. Managed
objects never have destructors.

When designing a type it is best to avoid using a Finalize method. There are several
reasons for this:

• Finalizable objects get promoted to older generations, which increases


memory pressure and prevents the object's memory from being collected
when the garbage collector determines the object is garbage. In addition, all
objects referred to directly or indirectly by this object get promoted as well.

• Finalizable objects take longer to allocate.

• Forcing the garbage collector to execute a Finalize method can significantly


hurt performance. Remember, each object is finalized. So if I have an array of
10,000 objects, each object must have its Finalize method called.

• Finalizable objects may refer to other (non-finalizable) objects, prolonging


their lifetime unnecessarily. In fact, you might want to consider breaking a
type into two different types: a lightweight type with a Finalize method that
doesn't refer to any other objects, and a separate type without a Finalize
method that does refer to other objects.

• You have no control over when the Finalize method will execute. The object
may hold on to resources until the next time the garbage collector runs.

• When an application terminates, some objects are still reachable and will not
have their Finalize method called. This can happen if background threads are
using the objects or if objects are created during application shutdown or
AppDomain unloading. In addition, by default, Finalize methods are not called
for unreachable objects when an application exits so that the application may
terminate quickly. Of course, all operating system resources will be reclaimed,
but any objects in the managed heap are not able to clean up gracefully. You
can change this default behavior by calling the System.GC type's
RequestFinalizeOnShutdown method. However, you should use this method
with care since calling it means that your type is controlling a policy for the
entire application.

• The runtime doesn't make any guarantees as to the order in which Finalize
methods are called. For example, let's say there is an object that contains a
pointer to an inner object. The garbage collector has detected that both
objects are garbage. Furthermore, say that the inner object's Finalize method
gets called first. Now, the outer object's Finalize method is allowed to access
the inner object and call methods on it, but the inner object has been
finalized and the results may be unpredictable. For this reason, it is strongly
recommended that Finalize methods not access any inner, member objects.

If you determine that your type must implement a Finalize method, then make sure
the code executes as quickly as possible. Avoid all actions that would block the
Finalize method, including any thread synchronization operations. Also, if you let any
exceptions escape the Finalize method, the system just assumes that the Finalize
method returned and continues calling other objects' Finalize methods.

When the compiler generates code for a constructor, the compiler automatically
inserts a call to the base type's constructor. Likewise, when a C++ compiler
generates code for a destructor, the compiler automatically inserts a call to the base
type's destructor. Finalize methods are different from destructors. The compiler has
no special knowledge about a Finalize method, so the compiler does not
automatically generate code to call a base type's Finalize method. If you want this
behavior-and frequently you do-then you must explicitly call the base type's Finalize
method from your type's Finalize method:

public class BaseObj


{
public BaseObj()
{
}
protected override void Finalize()
{
Console.WriteLine("In Finalize.");
base.Finalize(); // Call base type's Finalize
}
}

Note that you'll usually call the base type's Finalize method as the last statement in
the derived type's Finalize method. This keeps the base object alive as long as
possible. Since calling a base type Finalize method is common, C# has a syntax that
simplifies your work. In C#, the following code:

class MyObject
{
MyObject()
{
}
}

causes the compiler to generate this code:


class MyObject
{
protected override void Finalize()
{
base.Finalize();
}
}

Note that this C# syntax looks identical to the C++ language's syntax for defining a
destructor. But remember, C# doesn't support destructors. Don't let the identical
syntax fool you.

Finalization Internals

When an application creates a new object, the new operator allocates the memory
from the heap. If the object's type contains a Finalize method, then a pointer to the
object is placed on the finalization queue. The finalization queue is an internal data
structure controlled by the garbage collector. Each entry in the queue points to an
object that should have its Finalize method called before the object's memory can be
reclaimed.

Following fig shows a heap containing several objects. Some of these objects are
reachable from the application's roots, and some are not. When objects C, E, F, I,
and J were created, the system detected that these objects had Finalize methods and
pointers to these objects were added to the finalization queue.
When a GC occurs, objects B, E, G, H, I, and J are determined to be garbage. The
garbage collector scans the finalization queue looking for pointers to these objects.
When a pointer is found, the pointer is removed from the finalization queue and
appended to the freachable queue (pronounced "F-reachable"). The freachable queue
is another internal data structure controlled by the garbage collector. Each pointer in
the freachable queue identifies an object that is ready to have its Finalize method
called.

After the collection, the managed heap looks like following fig. Here, you see that the
memory occupied by objects B, G, and H has been reclaimed because these objects
did not have a Finalize method that needed to be called. However, the memory
occupied by objects E, I, and J could not be reclaimed because their Finalize method
has not been called yet.
There is a special runtime thread dedicated to calling Finalize methods. When the
freachable queue is empty (which is usually the case), this thread sleeps. But when
entries appear, this thread wakes, removes each entry from the queue, and calls
each object's Finalize method. Because of this, you should not execute any code in a
Finalize method that makes any assumption about the thread that's executing the
code. For example, avoid accessing thread local storage in the Finalize method.

The interaction of the finalization queue and the freachable queue is quite
fascinating. First, let me tell you how the freachable queue got its name. The f is
obvious and stands for finalization; every entry in the freachable queue should have
its Finalize method called. The "reachable" part of the name means that the objects
are reachable. To put it another way, the freachable queue is considered to be a root
just like global and static variables are roots. Therefore, if an object is on the
freachable queue, then the object is reachable and is not garbage.

In short, when an object is not reachable, the garbage collector considers the object
garbage. Then, when the garbage collector moves an object's entry from the
finalization queue to the freachable queue, the object is no longer considered
garbage and its memory is not reclaimed. At this point, the garbage collector has
finished identifying garbage. Some of the objects identified as garbage have been
reclassified as not garbage. The garbage collector compacts the reclaimable memory
and the special runtime thread empties the freachable queue, executing each
object's Finalize method.
The next time the garbage collector is invoked, it sees that the finalized objects are
truly garbage, since the application's roots don't point to it and the freachable queue
no longer points to it. Now the memory for the object is simply reclaimed. The
important thing to understand here is that two GCs are required to reclaim memory
used by objects that require finalization. In reality, more than two collections may be
necessary since the objects could get promoted to an older generation. Above fig
shows what the managed heap looks like after the second GC.

Dispose Method

Use this method to close or release unmanaged resources such as files, streams, and
handles held by an instance of the class that implements this interface. This method
is, by convention, used for all tasks associated with freeing resources held by an
object, or preparing an object for reuse.

When implementing this method, objects must seek to ensure that all held resources
are freed by propagating the call through the containment hierarchy. For example, if
an object A allocates an object B, and object B allocates an object C, then A's
Dispose implementation must call Dispose on B, which must in turn call Dispose on
C. Objects must also call the Dispose method of their base class if the base class
implements IDisposable.

If an object's Dispose method is called more than once, the object must ignore all
calls after the first one. The object must not throw an exception if its Dispose
method is called multiple times. Dispose can throw an exception if an error occurs
because a resource has already been freed and Dispose had not been called
previously.
Because the Dispose method must be called explicitly, objects that implement
IDisposable must also implement a finalizer to handle freeing resources when
Dispose is not called. By default, the garbage collector will automatically call an
object's finalizer prior to reclaiming its memory. However, once the Dispose method
has been called, it is typically unnecessary for the garbage collector to call the
disposed object's finalizer. To prevent automatic finalization, Dispose
implementations can call the GC.SuppressFinalize method.

Direct Control with System.GC

The System.GC type allows your application some direct control over the garbage
collector. You can query the maximum generation supported by the managed heap
by reading the GC.MaxGeneration property. Currently, the GC.MaxGeneration
property always returns 2.

It is also possible to force the garbage collector to perform a collection by calling one
of the two methods shown here:

void GC.Collect(Int32 Generation)


void GC.Collect()

The first method allows you to specify which generation to collect. You may pass any
integer from 0 to GC.MaxGeneration, inclusive. Passing 0 causes generation 0 to be
collected; passing 1 cause generation 1 and 0 to be collected; and passing 2 causes
generation 2, 1, and 0 to be collected. The version of the Collect method that takes
no parameters forces a full collection of all generations and is equivalent to calling:

GC.Collect(GC.MaxGeneration);

Under most circumstances, you should avoid calling any of the Collect methods; it is
best to just let the garbage collector run on its own accord. However, since your
application knows more about its behavior than the runtime does, you could help
matters by explicitly forcing some collections. For example, it might make sense for
your application to force a full collection of all generations after the user saves his
data file. I imagine Internet browsers performing a full collection when pages are
unloaded. You might also want to force a collection when your application is
performing other lengthy operations; this hides the fact that the collection is taking
processing time and prevents a collection from occurring when the user is interacting
with your application.

The GC type also offers a WaitForPendingFinalizers method. This method simply


suspends the calling thread until the thread processing the freachable queue has
emptied the queue, calling each object's Finalize method. In most applications, it is
unlikely that you will ever have to call this method.

Lastly, the garbage collector offers two methods that allow you to determine which
generation an object is currently in:

Int32 GetGeneration(Object obj)


Int32 GetGeneration(WeakReference wr)
The first version of GetGeneration takes an object reference as a parameter, and the
second version takes a WeakReference reference as a parameter. Of course, the
value returned will be somewhere between 0 and GC.MaxGeneration, inclusive.

This chapter rounds out your introduction to the core aspects of the C# language by
examining a number of advanced (but extremely useful) syntactic constructs. To
begin, you learn how to construct and use an indexer method. This C# mechanism
enables you to build custom types, which exposes internal subtypes using the
familiar bracket operator (i.e., []). If you have a C++ background, you will find that
creating a C# indexer method is analogous to overloading the [] operator on a C++
class. Once you learn how to build an indexer, you then examine how to overload
various operators (+, -, <, > and so forth) for a custom C# type.

This chapter then examines three techniques that enable the objects in your system
to engage in bidirectional communications. First, you learn about the C# "delegate"
keyword, which is little more than a type-safe function pointer. Once you learn how
to create and manipulate delegates, you are in a perfect position to investigate
the .NET event protocol, which is based on the delegation model. Finally, you
discover how the use of custom interfaces can also enable bidirectional
communications (which should ring a bell for those coming from a COM background).

I wrap up by examining how you can document your types using XML attributes, and
how the Visual Studio.NET IDE automatically generates Web-based documentation
for your projects. Although this might not qualify as a truly "advanced" technique, it
is a high note on which to end the chapter.

Building a Custom Indexer

At this point, you should feel confident building C# types using traditional OOP (refer
to Chapter 3) as well as interface-based programming techniques (refer to Chapter
4). In this chapter, I take some time to examine some additional aspects of C# that
you may not be readily failure with, beginning with the concept of an indexer. Most
programmers (such as yourself) are very familiar with the process of accessing
discrete items held within a standard array using the index (aka bracket) operator:

// Declare an array of integers.


int[] myInts = {10, 9, 100, 432, 9874};
// Use the [] operator to access each element.
for(int j = 0; j < myInts.Length; j++)
Console.WriteLine("Index {0} = {1}", j, myInts[j] j]);

The C# language supports the capability to build custom classes that may be
indexed just like an array of intrinsic types. It should be no big surprise that the
method that provides the capability to access items in this manner is termed an
"indexer." Before exploring how to create such a construct, let's begin by seeing one
in action. Assume you have added support for an indexer method to the Cars
container developed in the previous chapter. Observe the following usage:

// Indexers allow you to access items in an array array-like fashion.

public class CarApp


{
public static void Main()
{
// Assume the Cars type has an indexer method.
Cars carLot = new Cars();
// Make some cars and add them to the car lot.
carLot[0] = new Car("FeeFee", 200, 0);
carLot[1] = new Car("Clunker", 90, 0);
carLot[2] = new Car("Zippy", 30, 0);
// Now obtain and display each item.
for (int i = 0; i < 3; i++)
{
Console.WriteLine("Car number {0}:", i);
Console.WriteLine("Name: {0}", carLot[i].PetName);
Console.WriteLine("Max speed: {0}", carLot[i].MaxSpeed);
}
}
}

A test run would look something like Figure 5-1.

Figure 5-1. Accessing cars using an indexer

As you can see, indexers behave much like a custom collection supporting the
IEnumerator and IEnumerable interfaces. The only major difference is that rather
than A Comprehensive Guide to C# and the .NET Platform, ©2001 Andrew Troelsen
(Apress, ISBN: 1-893115-59-3) p. 5-3 accessing the contents using interface
references, you are able to manipulate the internal collection of automobiles just like
a standard array.

Now for the big question: How do you configure the Cars class (or any class) to do
so? The indexer itself is represented as a slightly mangled C# property. In its
simplest form, an indexer is created using the this[] syntax:

// Add the indexer to the existing class definition.

public class Cars : IEnumerator, IEnumerable


{

// Let's rollback to the basics and simply make use of a standard array
// to contain the cars. You are free to use an ArrayList if you desire…
private Car[] carArray;
public Cars()
{
carArray = new Car[10];
}
// The indexer returns a Car based on a numerical index.
public Car this[int pos]
{
// Accessor returns an item in the array.
get
{
if (pos < 0 || pos > 10)
throw new IndexOutOfRangeException("Out of range!");
else
return (carArray[pos]);
}
// Mutator populates the array.
set { carArray[pos] = value; }
}
}

Beyond the use of the "this" keyword, the indexer looks just like any other C#
property declaration. Do be aware that indexers do not provide any array-like
functionality beyond the use of the subscript operator. In other words, the object
user cannot write code such as:

// Use System.Array.Length? Nope!


Console.WriteLine("Cars in stock: {0}", carLot.Length);

To support this functionality, you would need to add your own Length property to the
Cars type, and delegate accordingly:

public class Cars


{
// Containment / delegation in action once again.
public int Length() { /* figure out number of non-null entries in array. */}
}

However, if you are in need of this functionality, you will find your task will be much
easier if you make direct use of one of the System.Collections types to hold your
internal items, rather than a simple array.

Understanding (and Using) Delegates

Up until this point, every sample application you have developed added various bits
of code to Main(), which (in some way or another) sent messages to a given object.
However, you have not yet examined how these objects can talk back to the object
that created them in the first place. In the "real world" it is quite common for the
objects in a system to engage in a two-way conversation. Thus, let's examine a
number of ways in which objects can be programmed to do this very thing.
As you may know, the Windows API makes frequent use of function pointers to
create entities termed "callback functions" or simply "callbacks." Using callbacks,
programmers are able to configure one function to report back to (call back) another
function in the application. The problem with standard C(++)callback functions is
that they represent nothing more than a simple memory address. Ideally, C(++)
callbacks could be configured to include additional type-safe information such as the
number of (and types of) parameters, return value, and calling convention. Sadly,
this is not the case in traditional C(++)/Win32 callback functions.

In C#, the callback technique is accomplished in a much safer and more


objectoriented manner using the "delegate" keyword. When you wish to create a
delegate in C#, you not only specify the name of the method, but the set of
parameters (if any) and return type as well. Under the hood, the "delegate" keyword
represents an instance of a class deriving from System.MulticastDelegate. Thus,
when you write: public delegate void PlayAcidHouse(object PaulOakenfold, int
volume); the C# compiler produces a new class, which looks something like the
following:

public class PlayAcidHouse : System System.MulticastDelegate


{
PlayAcidHouse(object target, int ptr);
// The synchronous Invoke() method.
public void virtual Invoke(object PaulOakenfold, int volume);
// You also receive an asynchronous version of the same callback.
public virtual IAsyncResult BeginInvoke(object PaulOakenfold, int volume,
AsyncCallback cb, object o);
public virtual void EndInvoke(IAsyncResult result);
}

Notice that the class that is created on your behalf contains two public methods that
enable you to synchronously or asynchronously work with the delegate (Invoke() and
BeginInvoke() respectively). To keep things simple, I will focus only on the
synchronous behavior of the MulticastDelegate type.

Building an Example Delegate

To illustrate the use of delegates, let's begin by updating the Car class to include two
new Boolean member variables. The first is used to determine if your automobile is
due for a wash (isDirty); the other represents if the car in question is in need of a
tire rotation (shouldRotate). To enable the object user to interact with this new state
data, Car also defines some additional properties and an updated constructor. Here
is the story so far:

// Another updated Car class.

public class Car


{
// NEW! Are we in need of a wash? Need to rotate tires?
private bool isDirty;
private bool shouldRotate;
// Extra para params to set bools.
public Car(string name, int max, int curr, bool dirty, bool rotate rotate)
{

isDirty = dirty;

shouldRotate = rotate;
}
public bool Dirty // Get and set isDirty.
{
get{ return isDirty; }
set{ isDirty = value; }
}
public bool Rotate // Get and set shouldRotate.
{
get{ return shouldRotate; }
set{ shouldRotate = value; }
}
}

Now, assume you have declared the following delegate (which again, is nothing more
than an object-oriented wrapper around a function pointer) within your current
namespace:

// This delegate is actually a class encapsulating a function pointer


// to 'some method' taking a Car as a parameter and returning void.
public delegate void CarDelegate(Car c);

Here, you have created a delegate named CarDelegate. The CarDelegate type
represents "some" function taking a Car as a parameter and returning void. If you
were to examine the internal representation of this type using ILDasm.exe, you
would see something like Figure 5-3 (notice the "extends" informational node).
Figure 5-3. C# delegates represent a class deriving from MulticastDelegate.

Delegates as Nested Types

Currently, your delegate is decoupled from its logically related Car type (given that
you have simply declared the CarDelegate type within the defining namespace).
While there is nothing horribly wrong with the approach, a more enlightened
alternative would be to define the CarDelegate directly within the Car class:

// This time, define the delegate as part of the class definition.


public class Car : Object
{
// This is represented as Car$CarDelegate (i.e., a nested type).
public delegate void CarDelegate(Car c);

Given that the "delegate" keyword produces a new class deriving from
System.MulticastDelegate, the CarDelegate is in fact a nested type definition! If you
check ILDasm.exe (see Figure 5-4), you will see the truth of the matter.

Figure 5-4. Nesting the delegate

Members of System.MutlicastDelegate

So to review thus far, when you create delegates, you indirectly build a type that
derives from System.MulticastDelegate (which by the way, derives from the
System.Delegate base class). Table 5-2 illustrates some interesting inherited
members to be aware of.

Table 5-2. Select Inherited Members

Inherited
Meaning in Life
Member
Method This property returns the name of the method pointed to.
If the method pointed to is a member of a class, this member
Target returns the name of the class. If the value returned from Target
equals null, the method pointed to is static.
This static method is used to build a delegate that points to a
Combine()
number of different functions.
Returns an array of Delegate types, each representing an entry in
GetInvocationList()
the list of function pointers.
This static method removes a delegate from the list of function
Remove()
pointers.

Multicast delegates are capable of pointing to any number of functions, because this
class has the capability to hold multiple function pointers using an internal linked list.
The function pointers themselves can be added to the linked list using the Combine()
method or the overloaded + operator. To remove a function from the internal list,
call Remove().

Using the CarDelegate

Now that you have a pointer to "some" function, you can create other functions that
take this delegate as a parameter. To illustrate, assume you have a new class named
Garage. This type maintains a collection of Car types contained in an ArrayList. Upon
creation, the ArrayList is filled with some initial Car types.

More importantly, the Garage class defines a public ProcessCars() method, which
takes a single argument of type Car.CarDelegate. In the implementation of
ProcessCars(), you pass each Car in your collection as a parameter to the "function
pointed to" by the delegate.

To help understand the inner workings of the delegation model, let's also make use
of two members defined by the System.MulticastDelegate class (Target and Method)
to determine exactly which function the delegate is currently pointing to. Here, then,
is the complete definition of the Garage class:

// The Garage class has a method that makes use of the CarDelegate.
public class Garage
{
// A list of all ca cars in the garage.
ArrayList theCars = new ArrayList();
// Create the cars in the garage.
public Garage()
{
// Recall, we updated the ctor to set isDirty and shouldRotate.
theCars.Add(new Car("Viper", 100, 0, true, false));
theCars.Add(new Car("Fred", 100, 0, false, false));
theCars.Add(new Car("BillyBob", 100, 0, false, true));
theCars.Add(new Car("Bart", 100, 0, true, true));
theCars.Add(new Car("Stan", 100, 0, false, true));
}
// This method takes a Car.CarDelegate as a parameter.his
// Therefore! 'proc' is nothing more than a function pointer! herefore!
public void ProcessCars(Car.CarDelegate proc)
{
// Diagnostics: Where are we forwarding the call?
Console.WriteLine("***** Calling: {0} *****", d.Method.ToString());
// Diagnostics: Are we calling an instance method or a static method?
if (proc.Target != null)
Console.WriteLine("-->Target: {0}", proc.Target.ToString());
else
Console.WriteLine("-->Target is a static method");
// Real Work: Now call the method, passing in each car.
foreach (Car c in theCars)
proc(c);
}
}

When the object user calls ProcessCars(), it will send in the name of the method that
should handle this request. For the sake of argument, assume these are static
members named WashCar() and RotateTires(). Consider the following usage:

// The garage delegates all work orders to these static functions


// (finding a good mechanic is always a problem…)
public class CarApp
{
// A target for the delegate.
public static void WashCar(Car c)
{
if (c.Dirty)
Console.WriteLine("Cleaning a car");
else
Console.WriteLine("This car is already clean...");
}

// Another target for the delegate.


public static void RotateTires(Car c)
{
if (c.Rotate)
Console.WriteLine("Tires have been rotated");
else
Console.WriteLine("Don't need to be rotated...");
}
public static int Main(string[] args)
{
// Make the garage.
Garage g = new Garage();
// Wash all dirty cars.
g.ProcessCars(new Car.CarDelegate(WashCar) WashCar));
// Rotate the tires.
g.ProcessCars(new Car.CarDelegate(RotateTires) RotateTires));
return 0;
}
}

Notice (of course) that the two static methods are an exact match to the delegate
type (void return value and a single Car argument). Also, recall that when you pass
in the name of your function as a constructor parameter, you are adding this item to
the internal linked list maintained by System.MulticastDelegate. Figure 5-5 shows
the output of this test run. (Notice the output messages supplied by Target and
Method properties.)

Figure 5-5. Delegate output, take one

Analyzing the Delegation Code

As you can see, the Main() method begins by creating an instance of the Garage
type.This class has been configured to delegate all work to other named static
functions. Now,when you write the following:

// Wash all dirty cars.


g.ProcessCars(new Car.CarDelegate(WashCar WashCar));

what you are effectively saying is "Add a pointer to the WashCar() function to the
CarDelegate type, and pass this delegate to Garage.ProcessCars()." Like most real-
world garages, the real work is delegated to another part of the system (which
explains why a 30-minute oil change takes 2 hours). Given this, you can assume that
ProcessCars() actually looks like the following under the hood:

// CarDelegate points to the WashCar function:


public void ProcessCars(Car.CarDelegate proc)
{
foreach (Car c in theCars)
proc(c); // proc(c) => CarApp.WashCar(c)
}

Likewise, if you say:

// Rotate the tires.


g.ProcessCars(new Car.CarDelegate(RotateTires RotateTires));

ProcessCars() can be understood as:

// CarDelegate points to the RotateTires function:


public void ProcessCars(Car.CarDelegate proc)
{
foreach (Car c in theCars)
proc(c); // proc(c) => CarApp.RotateTires(c)

Also notice that when you are calling ProcessCars(), you must create a new instance
of the custom delegate:

// Wash all dirty cars.


g.ProcessCars(new Car.CarDelegate(WashCar) WashCar));
// Rotate the tires.
g.ProcessCars(new Car.CarDelegate(RotateTires) RotateTires));

This might seem odd at first, given that a delegate represents a function pointer.
However, remember that this function pointer is represented by an instance of type
System.MulticastDelegate, and therefore must be "new-ed.

Multicasting

Recall that a multicast delegate is an object that is capable of calling any number of
functions. In the current example, you did not make use of this feature. Rather, you
made two calls to Garage.ProcessCars(), sending in a new instance of the
CarDelegate each time. To illustrate multicasting, assume you have updated Main()
to look like the following:

// Add two function pointers to the internal linked list.


public static int Main(string[] args)
{
// Make the garage.
Garage g = new Garage();
// Create two new delegates.
Car.CarDelegate wash = new Car.CarDelegate(WashCar);
Car.CarDelegate rotate = new Car.CarDelegate(RotateTires);
// The over overloaded + operator can be applied to multicast delegates.
loaded // The result is a new delegate that maintains pointers to
// both functions.
g.ProcessCars(wash + rotate rotate);
return 0;
}

Here, you begin by creating two new CarDelegate objects, each of which points to a
given function. When you call ProcessCars(), you are actually passing in a new
delegate, which holds each function pointer within the internal linked list (crazy
huh?). Do note that the + operator is simply a shorthand for calling the static
Delegate.Combine() method. Thus, you could write the following equivalent (but
uglier) code:

// The + operator has the same effect as calling the Combine() method.
g.ProcessCars((Car.CarDelegate)Delegate.Combine(wash, rotate));

Furthermore, if you wish to hang on to the new delegate for later use, you could
write
the following instead:

// Create two new delegates.


Car.CarDelegate wash = new Car.CarDelegate(WashCar);
Car.CarDelegate rotate = new Car.CarDelegate(RotateTires);
// Store the new delegate for later use.
MulticastDelegate d = wash + rotate;
// Send the new delegate into the ProcessCars() method.
g.ProcessCars((Car.CarDelegate)d (d);

Regardless of how you configure a multicast delegate, understand that when you call
Combine() (or use the overloaded + operator) you are adding a new function pointer
to the internal list. If you wish to remove an item from this internal linked list, you
can call the static Remove() method. The first parameter marks the delegate you
wish to manipulate, while the second parameter marks the item to remove:

// The static Remove() method returns a Delegate type.


Delegate washOnly = MulticastDelegate.Remove Remove(d, rotate);
g.ProcessCars((Car.CarDelegate)washOnly);

Before you view the output of this program, let's also update ProcessCars() to print
out each function pointer stored in the linked list using Delegate.GetInvocationList().
This method returns an array of Delegate objects, which you iterate over using
foreach:

// Now print out each member in the linked list.


public void ProcessCarsCar.(CarDelegate proc)
{
// Where are we passing the call?
foreach(Delegate d in proc.GetInvocationList GetInvocationList())
{
Console.WriteLine("***** Calling: " +
d.Method.ToString() + " *****");
}
}

The output is shown in Figure 5-6.


Figure 5-6. Delegate output, take two

Instance Methods as Callbacks

Currently, the CarDelegate type is storing pointers to static functions. This is not a
requirement of the delegate protocol. It is also possible to delegate a call to a
method defined on any object instance. To illustrate, assume that the WashCar() and
RotateTires() methods have now been moved into a new class named ServiceDept:

// We have now moved the static functions into a helper class.


public class ServiceDept
{
// Not static!
public void WashCar(Car c)
{
if (c.Dirty)
Console.WriteLine("Cleaning a car");
else
Console.WriteLine("This car is already clean...");
}
// Still not static!
public void RotateTires(Car c)
{
if (c.Rotate)
Console.WriteLine("Tires have been rotated");
else
Console.WriteLine("Don't need to be rotated...");
}
}

You could now update Main() as so:

// Delegate to instance methods of the ServiceDept type.


public static int Main(string[] args)
{
// Make the garage garage.
Garage g = new Garage();
// Make the service department.
ServiceDept sd = new ServiceDept();
// The garage delegates the work to the service department.
Car.CarDelegate wash = new Car.CarDelegate(sd.WashCar WashCar);
Car.CarDelegate rotate = new Car.CarDelegate(sd.RotateTires RotateTires);
MulticastDelegate d = wash + rotate;
// Tell the garage to do some work.
g.ProcessCars((Car.CarDelegate)d);
return 0;
}

Now notice the output in Figure 5-7 (check out the name of the target).

Figure 5-7. Delegating to instance methods

SOURCE CODE The CarDelegate project is located under the Chapter 5 subdirectory.

Understanding (and Using) Events

Delegates are fairly interesting constructs because you can resolve the name of a
function to call at runtime, rather than compile time. Admittedly, this syntactic
orchestration can take a bit of getting used to. However, because the ability for one
object to call back to another object is such a helpful construct, C# provides the
"event" keyword to lessen the burden of using delegates in the raw.

The most prevalent use of the event keyword would be found in GUI-based
applications, in which Button, TextBox, and Calendar widgets all report back to the
containing Form when a given action (such as clicking a Button) has occurred.
However, events are not limited to GUI-based applications. Indeed, they can be quite
helpful when creating "non-GUI" based projects (as you will now see).

Recall that the current implementation of Car.SpeedUp() (see Chapter 3) throws an


exception if the user attempts to increase the speed of an automobile that has
already been destroyed. This is a rather brute force way to deal with the problem,
given that the exception has the potential to halt the program's execution if the error
is not handled in an elegant manner. A better design would be to simply inform the
object user when the car has died using a custom event, and allow the caller to act
accordingly.

Let's reconfigure the Car to send two events to those who happen to be listening.
The first event (AboutToBlow) will be sent when the current speed is 10 miles below
the maximum speed. The second event (Exploded) will be sent when the user
attempts to speed up a car that is already dead. Establishing an event is a two-step
process. First, you need to define a delegate, which as you recall represents a
pointer to the method(s) to call when the event is sent. Next, you define the events
themselves using the "event" keyword. Here is the updated Car class (also notice
that I have added a private Boolean to represent the state of the car):

// This car can 'talk back' to the user.


public class Car
{
// Is the car alive or dead?
private bool dead;
// Holds the function(s) to call when the event occurs.
public delegate void EngineHandler(string msg);
// This car can send these events.
public static event EngineHandler Exploded Exploded;
public static event EngineHandler AboutToBlow AboutToBlow;
}

Firing an event (i.e., sending the event to those who happen to be listening) is as
simple as specifying the event by name and sending out any specified parameters.
To illustrate, update the previous implementation of SpeedUp() to send each event
accordingly (and remove the previous exception logic):

// Fire the correct event based on our current state of affairs.


public void SpeedUp(int delta)
{
// If the car is dead, send exploded event.
if(dead)
{
if(Exploded != null)
Exploded Exploded("Sorry, this car is dead...");
}
else
{
currSpeed += delta;
// Almost dead? Send about to blow ev event. ent.
if(10 = = maxSpeed - currSpeed)
if(AboutToBlow != null)
AboutToBlow AboutToBlow("Careful, approaching terminal speed!");
// Still OK! Proceed as usual.
if(currSpeed >= maxSpeed)
dead = true;
else
Console.WriteLine("\tCurrSpeed = {0}", currSpeed);
}
}

With this, you have configured the car to send two custom events (under the correct
conditions). You will see the usage of this new automobile in just a moment, but
first, let's check the event architecture in a bit more detail.

Events Under the Hood

A given event actually expands into two hidden public functions, one having an
"add_" prefix, the other having a "remove_" prefix. For example, the Exploded event
expands to the following methods:

// The following event expands to:


// add_Exploded()
// remove_Exploded()
//
public static event EngineHandler Exploded Exploded;

In addition to defining hidden add_XXX() and remove_XXX() methods, each event


also actually maps to a private static class, which associates the corresponding
delegate to a given event. In this way, when an event is raised, each method
maintained by the delegate will be called. This is a convenient way to allow an object
to broadcast the event to multiple "event sinks."

To illustrate, check out Figure 5-8, a screenshot of the Car type as seen through the
eyes of ILDasm.exe.
Figure 5-8. Events under the hood

As you can see, each event (Exploded and AboutToBlow) is internally represented as
the following members:

• A private static class


• An add_XXX() method
• A remove_XXX() method

If you were to check out the IL instructions behind add_AboutToBlow(), you would
find the following (note the call to Delegate.Combine() is handled on your behalf):

.method public hidebysig specialname static


void add_AboutToBlow(class CarEvents.Car/EngineHandler 'value') cil managed
synchronized
{
// Code size 22 (0x16)
.maxstack 8
IL_0000: ldsfld class CarEvents.Car/EngineHandler
CarEvents.Car::AboutToBlow
IL_0005: ldarg.0
IL_0006: call class [mscorlib]System.Delegate
[mscorlib]System.Delegate::Combine Combine(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
IL_000b: castclass CarEvents.Car/EngineHandler
IL_0010: stsfld class CarEvents.Car/EngineHandler
CarEvents.Car::AboutToBlow
IL_0015: ret
} // end of method Car::add_AboutToBlow

As you would expect, remove_AboutToBlow() will make the call to


Delegate.Remove() automatically:

.method public hidebysig specialname static


void remove_AboutToBlow AboutToBlow(class CarEvents.Car/EngineHandler
'value')cil managed
synchronized
{
// Code size 22 (0x16)
.maxstack 8
IL_0000: ldsfld class CarEvents.Car/EngineHandler
CarEvents.Car::AboutToBlow
IL_0005: ldarg.0
IL_0006: call class [mscorlib]System.Delegate
[mscorlib]System.Delegate::Remove Remove(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
IL_000b: castclass CarEvents.Car/EngineHandler
IL_0010: stsfld class CarEvents.Car/EngineHandler
CarEvents.Car::AboutToBlow
IL_0015: ret
} // end of method Car::remove_AboutToBlow

The IL instructions for the event itself make use of the [.addon] and [.removeon]
tags to establish the correct add_XXX and remove_XXX methods (also note the static
private class is mentioned by name):

.event nt CarEvents.Car/EngineHandler AboutToBlow


{
.addon void CarEvents.Car::add_AboutToBlow AboutToBlow(class
CarEvents.Car/EngineHandler)
.removeon
void CarEvents.Car::remove_AboutToBlow AboutToBlow(class
CarEvents.Car/EngineHandler)
} // end of event Car::AboutToBlow
So, now that you understand how to build a class that can send events, the next big
question is how you can configure an object to receive these events.

Listening to Incoming Events

Assume you have now created an instance of the Car class and wish to listen to the
events it is capable of sending. The goal is to create a method that represents the
"event sink" (i.e., the method called by the delegate). To do so, you need to call the
correct add_XXX() method to ensure that your method is added to the list of function
pointers maintained by your delegate. However, you do not call add_XXX() and
remove_XXX() directly, but rather use the overloaded += and -= operators.
Basically, when you wish to listen to an event, follow the pattern shown here:

// I'm listening…
// ObjectVariable.EventName += new ObjectVariable.DelegateName(functionToCall);
//
Car.Exploded += new Car.EngineHandler(OnBlowUp OnBlowUp);

When you wish to detach from a source of events, use the -= operator:

// Shut up already!
// ObjectVariable.EventName -= new ObjectVariable.DelegateName(functionToCall);
//
Car.Exploded -= new Car.EngineHandler(OnBlowUp OnBlowUp);

Here is a complete example (output is shown in Figure 5-9):

// Make a car and listen to the events.


public class CarApp
{
public static int Main(string[] args)
{
Car c1 = new Car("SlugBug", 100, 10);
// Hook into events.
Car.Exploded += new Car.EngineHandler(OnBlowUp);
Car.AboutToBlow += new Car.EngineHandler(OnAboutToBlow);
// Speed up (this will generate the events.)
for (int i = 0; i < 10; i++) c1.SpeedUp(20);
// Detach fro from events.
Car.Exploded -= new Car.EngineHandler(OnBlowUp);
Car.Exploded -= new Car.EngineHandler(OnAboutToBlow);
// No response!
for (int i = 0; i < 10; i++) c1.SpeedUp(20);
return 0;
}
// OnBlo OnBlowUp event sink.
public static void OnBlowUp(string s)
{
Console.WriteLine("Message from car: {0}", s);
}
// OnAboutToBlow event sink.
public static void OnAboutToBlow(string s)
{
Console.WriteLine("Message from car: {0}", s);
}
}

Figure 5-9. Handling your Car's event set

If you wish to have multiple event sinks called by a given event, simply repeat the
process:

// Multiple event sinks.


public class CarApp
{
public static int Main(string[] args)
{
// Make a car as usual.
Car c1 = new Car("SlugBug", 100, 10);
// Hook into events.
Car.Exploded += new Car.EngineHandler(OnBlowUp);
Car.Exploded += new Car.EngineHandler(OnBlowUp2 OnBlowUp2); );
Car.AboutToBlow += new Car.EngineHandler(OnAboutToBlow);
// Speed up (this will generate the events.)
for(int i = 0; i < 10; i++)
c1.SpeedUp(20);
// Detach from events.
Car.Exploded -= new Car.EngineHandler(OnBlowUp);
Car.Exploded -= new Car.EngineHandler(OnBlowUp2);
Car.Exploded -= new Car.EngineHandler(OnAboutToBlow);
}
// OnBlowUp event sink A.
public static void OnBlowUp(string s)
{
Console.WriteLine("Message from car: {0}", s);
}
// OnBlowUp event sink B.
public static void OnBlowUp2(string s)
{
Console.WriteLine("-->AGAIN I say: {0}", s);
}
// OnAboutToBlow event sink.
public static void OnAboutToBlow(string s)
{
Console.WriteLine("Message from car: {0}", s);
}
}

Now, when the Exploded event is sent, the associated delegate calls OnBlowUp() as
well as OnBlowUp2(), as shown in Figure 5-10.

Figure 5-10. Working with multiple event handlers

Objects as Event Sinks

At this point, you have the background to build objects that can participate in a two-
way conversation. However, understand that you are free to build a helper object to
respond to an object's event set, much in the same way that you created a helper
class to be called by all delegates. For example, let's move your event sink methods
out of the CarApp class and into a new class named CarEventSink:

// Car event sink


public class CarEventSink
{
// OnBlowUp event handler.
public void OnBlowUp(string s)
{
Console.WriteLine("Message from car: {0}", s);
}
// OnBlowUp event handler version 2.
public void OnBlowUp2(string s)
{
Console.WriteLine("-->AGAIN I say: {0}", s);
}
// OnAboutToBlow handler.
public void OnAboutToBlow(string s)
{
Console.WriteLine("Message from car: {0}", s);
}
}

The CarApp class is then a bit more self-contained, as the event sink methods have
been pulled out of the CarApp definition and into their own custom type. Here is the
update:

// Note the creation and use of the CarEventSink.


public class CarApp
{
public static int Main(string[] args)
{
Car c1 = new Car("SlugBug", 100, 10);
// Make the sink object.
CarEventSink sink = new CarEventSink();
// Hook into events using sink object.
Car.Exploded += new Car.EngineHandler(sink.OnBlowUp);
Car.Exploded += new Car.EngineHandler(sink.OnBlowUp2);
Car.AboutToBlow += new Car.EngineHandler(sink.OnAboutToBlow);
for (int i = 0; i < 10; i++)
c1.SpeedUp(20);
// Detach from events using sink object.
Car.Exploded -= new Car.EngineHandler(sink.OnBlowUp);
Car.Exploded -= new Car.EngineHandler(sink.OnBlowUp2);
Car.Exploded -= new Car.EngineHandler(sink.OnAboutToBlow);
return 0;
}
}

The output is (of course) identical.

SOURCE CODE The CarEvents project is located under the Chapter 5 subdirectory.

Designing an Event Interface

COM programmers may be familiar with the notion of defining and implementing
"callback interfaces." This technique allows a COM client to receive events from a
coclass using a custom COM interface, and is often used to bypass the overhead
imposed by the official COM connection point architecture. For an illustration of using
the interface as a callback, let's examine how callback interfaces can be created
using C# (and .NET in general). Consider this last topic a bonus section, which
proves the point that there is always more than one way to solve a problem.

First, let's keep the same assumption that the Car type wishes to inform the outside
world when it is about to blow (current speed is 10 miles below the maximum speed)
and has exploded. However, this time you will not be using the "delegate" or "event"
keywords, but rather the following custom interface:

// The engine event interface.


public interface IEngineEve IEngineEvents nts
{
void AboutToBlow(string msg);
void Exploded(string msg);
}

This interface will be implemented by a sink object, on which the Car will make calls.

Here is a sample implementation:

// Car event sink.


public class CarEventSink : IEngineEvents
{
public void AboutToBlow(string msg)
{
Console.WriteLine(msg);
}
public void Exploded(string msg)
{
Console.WriteLine(msg);
}
}

Now that you have an object that implements the event interface, your next task is
to pass a reference to this sink into the Car. The Car holds onto the reference, and
makes calls back on the sink when appropriate. In order to allow the Car to obtain a
reference to the sink, you can assume some method has been added to the default
public interface.

In keeping with the COM paradigm, let's call this method Advise(). When the object
user wishes to detach from the event source, he may call another method
(Unadvise() in COM-speak). In order to allow the object user to register multiple
event sinks, let's assume that the Car maintains an ArrayList to represent each
outstanding connection (analogous to the array of IUnknown* interfaces used with
classic COM connection points). Here is the story so far:

// This Car does not make any use of C# delegates or events.


public class Car
{
// The set of connected sinks.
ArrayList itfConnections = new ArrayList();
// Attach or disconnect from the source of events.
public void Advise(IEngineEvents itfClientImpl)
{
itfConnections.Add(itfClientImpl);
}
public void Unadvise(IEngineEvents itfClientImpl)
{
itfConnections.Remove(itfClientImpl);
}
}

Now, Car.SpeedUp() can be retrofitted to iterate over the list of connections and fire
the correct notification when appropriate (i.e., call the correct method on the sink):

// Interface based event protocol!


//
class Car
{
public void SpeedUp(int delta)
{
// If the car is dead, send exploded event to each sink.
if (dead)
{
foreach (IEngineEvents e in itfConnections)
e.Exploded("Sorry, this car is dead...");
}
else
{
currSpeed += delta;
// Dude, you're almost dead! Proceed with caution!
if (10 = maxSpeed - currSpeed)
{
foreach (IEngineEvents e in itfConnections)
e.AboutToBlow("Careful buddy! Gonna blow!");
}
// Still OK!
if (currSpeed >= maxSpeed)
dead = true;
else
Console.WriteLine("\tCurrSpeed = {0}", currSpeed);
}
}
}

The following is some client-side code, now making use of a callback interface to
listen to the Car events:

// Make a car and listen to the events.


public class CarApp
{
public static int Main(string[] args)
{
Car c1 = new Car("SlugBug", 100, 10);
// Make sink object.
CarEventSink sink = new CarEventSink();
// Pass the Car a reference to the sink.
// (The lab solution registers multiple sinks…).
c1.Advise(sink);
// Speed up (this will generate the events.)
for (int i = 0; i < 10; i++)
c1.SpeedUp(20);
// Detach from events.
c1.Unadvise(sink);
return 0;
}
}

The output should look very familiar (see Figure 5-11).

Figure 5-11. Interfaces as an event protocol


The skeleton of object - oriented programming is of course the concepts of class. This C# tutorial
on OOPS explains classes and their importance in implementation of object oriented principles.

Any language can be called object oriented if it has data and method that use data
encapsulated in items named objects. An object oriented programming method has many
advantages, some of them are flexibility and code reusability.

All the programming languages supporting Object oriented Programming will be supporting
these three main concepts:

1. Encapsulation
2. Inheritance
3. Polymorphism

Encapsulation in C#:

Encapsulation is process of keeping data and methods together inside objects. In this way
developer must define some methods of object's interaction. In C# , encapsulation is realized
through the classes. A Class can contain data structures and methods. Consider the following
class.

public class Aperture


{

public Aperture()
{

protected double height;


protected double width;
protected double thickness;
public double GetVolume()
{

double volume = height*width*thickness;


if(volume<0)
return 0;
return volume;

In this example we encapsulate some data such as height, width, thickness and method
GetVolume. Other methods or objects can interact with this object through methods that have
public access modifier. It must be done using . operator.

Inheritance in C#:

In a few words, Inheritance is the process of creation new classes from already existing
classes. The inheritance feature allows us to reuse some parts of code. So, now we have some
derived class that inherits base class's members. Consider the following code snippet:

public class Door : Aperture


{

public Door() : base()


{

public bool isOutside = true;

As you see to inherit one class from another, we need to write base class name after : symbol.
Next thing that was done in code Door () constructor also inherits base class constructor. And at
last we add new private field. All members of Aperture class are also in Door class. We can
inherit all the members that has access modifier higher than protected.

Polymorphism in C#:

Polymorphism is possibility to change behavior with objects depending of object's data type. In
C# polymorphism realizes through the using of keyword virtual and override. Let look on the
example of code:

public virtual void Out()


{
Console.WriteLine("Aperture virtual method called");
}
//This method is defined in Aperture class.
public override void Out()
{
Console.WriteLine("Door virtual method called");
}

Now we need to re-define it in our derived Door class. The usage of virtual methods can be
clarified when we creating an instance of derived class from the base class:

Aperture ap = new Door();


ap.Out();

In such cases, the runtime keeps record of all the virtual function details in a table called
VMT(Virtual Method Table) and then in runtime dynamically picks the correct version of the
function to be used. Here it uses Out() method from derived class of course

Writing a Web application with ASP.NET is unbelievably easy. So easy, many


developers don't take the time to structure their applications for great performance. In this
article, I'm going to present 10 tips for writing high-performance Web apps. I'm not
limiting my comments to ASP.NET applications because they are just one subset of Web
applications. This article won't be the definitive guide for performance-tuning Web
applications—an entire book could easily be devoted to that. Instead, think of this as a
good place to start.
Before becoming a workaholic, I used to do a lot of rock climbing. Prior to any big climb,
I'd review the route in the guidebook and read the recommendations made by people who
had visited the site before. But, no matter how good the guidebook, you need actual rock
climbing experience before attempting a particularly challenging climb. Similarly, you
can only learn how to write high-performance Web applications when you're faced with
either fixing performance problems or running a high-throughput site.
My personal experience comes from having been an infrastructure Program Manager on
the ASP.NET team at Microsoft, running and managing www.asp.net, and helping
architect Community Server, which is the next version of several well-known ASP.NET
applications (ASP.NET Forums, .Text, and nGallery combined into one platform). I'm
sure that some of the tips that have helped me will help you as well.
You should think about the separation of your application into logical tiers. You might
have heard of the term 3-tier (or n-tier) physical architecture. These are usually
prescribed architecture patterns that physically divide functionality across processes
and/or hardware. As the system needs to scale, more hardware can easily be added. There
is, however, a performance hit associated with process and machine hopping, thus it
should be avoided. So, whenever possible, run the ASP.NET pages and their associated
components together in the same application.
Because of the separation of code and the boundaries between tiers, using Web services
or remoting will decrease performance by 20 percent or more.
The data tier is a bit of a different beast since it is usually better to have dedicated
hardware for your database. However, the cost of process hopping to the database is still
high, thus performance on the data tier is the first place to look when optimizing your
code.
Before diving in to fix performance problems in your applications, make sure you profile
your applications to see exactly where the problems lie. Key performance counters (such
as the one that indicates the percentage of time spent performing garbage collections) are
also very useful for finding out where applications are spending the majority of their
time. Yet the places where time is spent are often quite unintuitive.
There are two types of performance improvements described in this article: large
optimizations, such as using the ASP.NET Cache, and tiny optimizations that repeat
themselves. These tiny optimizations are sometimes the most interesting. You make a
small change to code that gets called thousands and thousands of times. With a big
optimization, you might see overall performance take a large jump. With a small one, you
might shave a few milliseconds on a given request, but when compounded across the
total requests per day, it can result in an enormous improvement.

Performance on the Data Tier


When it comes to performance-tuning an application, there is a single litmus test you can
use to prioritize work: does the code access the database? If so, how often? Note that the
same test could be applied for code that uses Web services or remoting, too, but I'm not
covering those in this article.
If you have a database request required in a particular code path and you see other areas
such as string manipulations that you want to optimize first, stop and perform your litmus
test. Unless you have an egregious performance problem, your time would be better
utilized trying to optimize the time spent in and connected to the database, the amount of
data returned, and how often you make round-trips to and from the database.
With that general information established, let's look at ten tips that can help your
application perform better. I'll begin with the changes that can make the biggest
difference.

Tip 1—Return Multiple Resultsets


Review your database code to see if you have request paths that go to the database more
than once. Each of those round-trips decreases the number of requests per second your
application can serve. By returning multiple resultsets in a single database request, you
can cut the total time spent communicating with the database. You'll be making your
system more scalable, too, as you'll cut down on the work the database server is doing
managing requests.
While you can return multiple resultsets using dynamic SQL, I prefer to use stored
procedures. It's arguable whether business logic should reside in a stored procedure, but I
think that if logic in a stored procedure can constrain the data returned (reduce the size of
the dataset, time spent on the network, and not having to filter the data in the logic tier),
it's a good thing.
Using a SqlCommand instance and its ExecuteReader method to populate strongly typed
business classes, you can move the resultset pointer forward by calling NextResult.
Figure 1 shows a sample conversation populating several ArrayLists with typed classes.
Returning only the data you need from the database will additionally decrease memory
allocations on your server.
Figure 1 Extracting Multiple Resultsets from a DataReader
// read the first resultset reader = command.ExecuteReader(); // read
the data from that resultset while (reader.Read())
{ suppliers.Add(PopulateSupplierFromIDataReader( reader )); } // read
the next resultset reader.NextResult(); // read the data from that
second resultset while (reader.Read())
{ products.Add(PopulateProductFromIDataReader( reader )); }

Tip 2—Paged Data Access


The ASP.NET DataGrid exposes a wonderful capability: data paging support. When
paging is enabled in the DataGrid, a fixed number of records is shown at a time.
Additionally, paging UI is also shown at the bottom of the DataGrid for navigating
through the records. The paging UI allows you to navigate backwards and forwards
through displayed data, displaying a fixed number of records at a time.
There's one slight wrinkle. Paging with the DataGrid requires all of the data to be bound
to the grid. For example, your data layer will need to return all of the data and then the
DataGrid will filter all the displayed records based on the current page. If 100,000
records are returned when you're paging through the DataGrid, 99,975 records would be
discarded on each request (assuming a page size of 25). As the number of records grows,
the performance of the application will suffer as more and more data must be sent on
each request.
One good approach to writing better paging code is to use stored procedures. Figure 2
shows a sample stored procedure that pages through the Orders table in the Northwind
database. In a nutshell, all you're doing here is passing in the page index and the page
size. The appropriate resultset is calculated and then returned.
Figure 2 Paging Through the Orders Table
CREATE PROCEDURE northwind_OrdersPaged ( @PageIndex int, @PageSize
int ) AS BEGIN DECLARE @PageLowerBound int DECLARE @PageUpperBound int
DECLARE @RowsToReturn int -- First set the rowcount SET @RowsToReturn =
@PageSize * (@PageIndex + 1) SET ROWCOUNT @RowsToReturn -- Set the page
bounds SET @PageLowerBound = @PageSize * @PageIndex SET @PageUpperBound
= @PageLowerBound + @PageSize + 1 -- Create a temp table to store the
select results CREATE TABLE #PageIndex ( IndexId int IDENTITY (1, 1)
NOT NULL, OrderID int ) -- Insert into the temp table INSERT INTO
#PageIndex (OrderID) SELECT OrderID FROM Orders ORDER BY OrderID DESC
-- Return total count SELECT COUNT(OrderID) FROM Orders -- Return paged
results SELECT O.* FROM Orders O, #PageIndex PageIndex WHERE O.OrderID
= PageIndex.OrderID AND PageIndex.IndexID > @PageLowerBound AND
PageIndex.IndexID < @PageUpperBound ORDER BY PageIndex.IndexID END
In Community Server, we wrote a paging server control to do all the data paging. You'll
see that I am using the ideas discussed in Tip 1, returning two resultsets from one stored
procedure: the total number of records and the requested data.
The total number of records returned can vary depending on the query being executed.
For example, a WHERE clause can be used to constrain the data returned. The total
number of records to be returned must be known in order to calculate the total pages to be
displayed in the paging UI. For example, if there are 1,000,000 total records and a
WHERE clause is used that filters this to 1,000 records, the paging logic needs to be
aware of the total number of records to properly render the paging UI.

Tip 3—Connection Pooling


Setting up the TCP connection between your Web application and SQL Server™ can be
an expensive operation. Developers at Microsoft have been able to take advantage of
connection pooling for some time now, allowing them to reuse connections to the
database. Rather than setting up a new TCP connection on each request, a new
connection is set up only when one is not available in the connection pool. When the
connection is closed, it is returned to the pool where it remains connected to the database,
as opposed to completely tearing down that TCP connection.
Of course you need to watch out for leaking connections. Always close your connections
when you're finished with them. I repeat: no matter what anyone says about garbage
collection within the Microsoft® .NET Framework, always call Close or Dispose
explicitly on your connection when you are finished with it. Do not trust the common
language runtime (CLR) to clean up and close your connection for you at a
predetermined time. The CLR will eventually destroy the class and force the connection
closed, but you have no guarantee when the garbage collection on the object will actually
happen.
To use connection pooling optimally, there are a couple of rules to live by. First, open the
connection, do the work, and then close the connection. It's okay to open and close the
connection multiple times on each request if you have to (optimally you apply Tip 1)
rather than keeping the connection open and passing it around through different methods.
Second, use the same connection string (and the same thread identity if you're using
integrated authentication). If you don't use the same connection string, for example
customizing the connection string based on the logged-in user, you won't get the same
optimization value provided by connection pooling. And if you use integrated
authentication while impersonating a large set of users, your pooling will also be much
less effective. The .NET CLR data performance counters can be very useful when
attempting to track down any performance issues that are related to connection pooling.
Whenever your application is connecting to a resource, such as a database, running in
another process, you should optimize by focusing on the time spent connecting to the
resource, the time spent sending or retrieving data, and the number of round-trips.
Optimizing any kind of process hop in your application is the first place to start to
achieve better performance.
The application tier contains the logic that connects to your data layer and transforms
data into meaningful class instances and business processes. For example, in Community
Server, this is where you populate a Forums or Threads collection, and apply business
rules such as permissions; most importantly it is where the Caching logic is performed.
Tip 4—ASP.NET Cache API
One of the very first things you should do before writing a line of application code is
architect the application tier to maximize and exploit the ASP.NET Cache feature.
If your components are running within an ASP.NET application, you simply need to
include a reference to System.Web.dll in your application project. When you need access
to the Cache, use the HttpRuntime.Cache property (the same object is also accessible
through Page.Cache and HttpContext.Cache).

There are several rules for caching data. First, if data can be used more than once it's a
good candidate for caching. Second, if data is general rather than specific to a given
request or user, it's a great candidate for the cache. If the data is user- or request-specific,
but is long lived, it can still be cached, but may not be used as frequently. Third, an often
overlooked rule is that sometimes you can cache too much. Generally on an x86 machine,
you want to run a process with no higher than 800MB of private bytes in order to reduce
the chance of an out-of-memory error. Therefore, caching should be bounded. In other
words, you may be able to reuse a result of a computation, but if that computation takes
10 parameters, you might attempt to cache on 10 permutations, which will likely get you
into trouble. One of the most common support calls for ASP.NET is out-of-memory
errors caused by overcaching, especially of large datasets.Common Performance Myths

One of the most common myths is that C# code is faster than Visual Basic code. There is
a grain of truth in this, as it is possible to take several performance-hindering actions in
Visual Basic that are not possible to accomplish in C#, such as not explicitly declaring
types. But if good programming practices are followed, there is no reason why Visual
Basic and C# code cannot execute with nearly identical performance. To put it more
succinctly, similar code produces similar results.
Another myth is that codebehind is faster than inline, which is absolutely false. It doesn't
matter where your code for your ASP.NET application lives, whether in a codebehind file
or inline with the ASP.NET page. Sometimes I prefer to use inline code as changes don't
incur the same update costs as codebehind. For example, with codebehind you have to
update the entire codebehind DLL, which can be a scary proposition.
Myth number three is that components are faster than pages. This was true in Classic
ASP when compiled COM servers were much faster than VBScript. With ASP.NET,
however, both pages and components are classes. Whether your code is inline in a page,
within a codebehind, or in a separate component makes little performance difference.
Organizationally, it is better to group functionality logically this way, but again it makes
no difference with regard to performance.
The final myth I want to dispel is that every functionality that you want to occur between
two apps should be implemented as a Web service. Web services should be used to
connect disparate systems or to provide remote access to system functionality or
behaviors. They should not be used internally to connect two similar systems. While easy
to use, there are much better alternatives. The worst thing you can do is use Web services
for communicating between ASP and ASP.NET applications running on the same server,
which I've witnessed all too frequently.
Figure 3 ASP.NET Cache
There are a several great features of the Cache that you need to know. The first is that the
Cache implements a least-recently-used algorithm, allowing ASP.NET to force a Cache
purge—automatically removing unused items from the Cache—if memory is running
low. Secondly, the Cache supports expiration dependencies that can force invalidation.
These include time, key, and file. Time is often used, but with ASP.NET 2.0 a new and
more powerful invalidation type is being introduced: database cache invalidation. This
refers to the automatic removal of entries in the cache when data in the database changes.
For more information on database cache invalidation, see Dino Esposito's Cutting Edge
column in the July 2004 issue of MSDN®Magazine. For a look at the architecture of the
cache, see Figure 3.

Tip 5—Per-Request Caching


Earlier in the article, I mentioned that small improvements to frequently traversed code
paths can lead to big, overall performance gains. One of my absolute favorites of these is
something I've termed per-request caching.
Whereas the Cache API is designed to cache data for a long period or until some
condition is met, per-request caching simply means caching the data for the duration of
the request. A particular code path is accessed frequently on each request but the data
only needs to be fetched, applied, modified, or updated once. This sounds fairly
theoretical, so let's consider a concrete example.
In the Forums application of Community Server, each server control used on a page
requires personalization data to determine which skin to use, the style sheet to use, as
well as other personalization data. Some of this data can be cached for a long period of
time, but some data, such as the skin to use for the controls, is fetched once on each
request and reused multiple times during the execution of the request.
To accomplish per-request caching, use the ASP.NET HttpContext. An instance of
HttpContext is created with every request and is accessible anywhere during that request
from the HttpContext.Current property. The HttpContext class has a special Items
collection property; objects and data added to this Items collection are cached only for the
duration of the request. Just as you can use the Cache to store frequently accessed data,
you can use HttpContext.Items to store data that you'll use only on a per-request basis.
The logic behind this is simple: data is added to the HttpContext.Items collection when it
doesn't exist, and on subsequent lookups the data found in HttpContext.Items is simply
returned.

Tip 6—Background Processing


The path through your code should be as fast as possible, right? There may be times
when you find yourself performing expensive tasks on each request or once every n
requests. Sending out e-mails or parsing and validation of incoming data are just a few
examples.
When tearing apart ASP.NET Forums 1.0 and rebuilding what became Community
Server, we found that the code path for adding a new post was pretty slow. Each time a
post was added, the application first needed to ensure that there were no duplicate posts,
then it had to parse the post using a "badword" filter, parse the post for emoticons,
tokenize and index the post, add the post to the moderation queue when required, validate
attachments, and finally, once posted, send e-mail notifications out to any subscribers.
Clearly, that's a lot of work.
It turns out that most of the time was spent in the indexing logic and sending e-mails.
Indexing a post was a time-consuming operation, and it turned out that the built-in
System.Web.Mail functionality would connect to an SMTP server and send the e-mails
serially. As the number of subscribers to a particular post or topic area increased, it would
take longer and longer to perform the AddPost function.
Indexing e-mail didn't need to happen on each request. Ideally, we wanted to batch this
work together and index 25 posts at a time or send all the e-mails every five minutes. We
decided to use the same code I had used to prototype database cache invalidation for what
eventually got baked into Visual Studio® 2005.
The Timer class, found in the System.Threading namespace, is a wonderfully useful, but
less well-known class in the .NET Framework, at least for Web developers. Once created,
the Timer will invoke the specified callback on a thread from the ThreadPool at a
configurable interval. This means you can set up code to execute without an incoming
request to your ASP.NET application, an ideal situation for background processing. You
can do work such as indexing or sending e-mail in this background process too.
There are a couple of problems with this technique, though. If your application domain
unloads, the timer instance will stop firing its events. In addition, since the CLR has a
hard gate on the number of threads per process, you can get into a situation on a heavily
loaded server where timers may not have threads to complete on and can be somewhat
delayed. ASP.NET tries to minimize the chances of this happening by reserving a certain
number of free threads in the process and only using a portion of the total threads for
request processing. However, if you have lots of asynchronous work, this can be an issue.
There is not enough room to go into the code here, but you can download a digestible
sample at www.rob-howard.net. Just grab the slides and demos from the Blackbelt
TechEd 2004 presentation.
Tip 7—Page Output Caching and Proxy Servers
ASP.NET is your presentation layer (or should be); it consists of pages, user controls,
server controls (HttpHandlers and HttpModules), and the content that they generate. If
you have an ASP.NET page that generates output, whether HTML, XML, images, or any
other data, and you run this code on each request and it generates the same output, you
have a great candidate for page output caching.
By simply adding this line to the top of your page
<%@ Page OutputCache VaryByParams="none" Duration="60" %>
you can effectively generate the output for this page once and reuse it multiple times for
up to 60 seconds, at which point the page will re-execute and the output will once be
again added to the ASP.NET Cache. This behavior can also be accomplished using some
lower-level programmatic APIs, too. There are several configurable settings for output
caching, such as the VaryByParams attribute just described. VaryByParams just happens
to be required, but allows you to specify the HTTP GET or HTTP POST parameters to
vary the cache entries. For example, default.aspx?Report=1 or default.aspx?Report=2
could be output-cached by simply setting VaryByParam="Report". Additional parameters
can be named by specifying a semicolon-separated list.
Many people don't realize that when the Output Cache is used, the ASP.NET page also
generates a set of HTTP headers that downstream caching servers, such as those used by
the Microsoft Internet Security and Acceleration Server or by Akamai. When HTTP
Cache headers are set, the documents can be cached on these network resources, and
client requests can be satisfied without having to go back to the origin server.
Using page output caching, then, does not make your application more efficient, but it
can potentially reduce the load on your server as downstream caching technology caches
documents. Of course, this can only be anonymous content; once it's downstream, you
won't see the requests anymore and can't perform authentication to prevent access to it.

Tip 8—Run IIS 6.0 (If Only for Kernel Caching)


If you're not running IIS 6.0 (Windows Server™ 2003), you're missing out on some great
performance enhancements in the Microsoft Web server. In Tip 7, I talked about output
caching. In IIS 5.0, a request comes through IIS and then to ASP.NET. When caching is
involved, an HttpModule in ASP.NET receives the request, and returns the contents from
the Cache.
If you're using IIS 6.0, there is a nice little feature called kernel caching that doesn't
require any code changes to ASP.NET. When a request is output-cached by ASP.NET,
the IIS kernel cache receives a copy of the cached data. When a request comes from the
network driver, a kernel-level driver (no context switch to user mode) receives the
request, and if cached, flushes the cached data to the response, and completes execution.
This means that when you use kernel-mode caching with IIS and ASP.NET output
caching, you'll see unbelievable performance results. At one point during the Visual
Studio 2005 development of ASP.NET, I was the program manager responsible for
ASP.NET performance. The developers did the magic, but I saw all the reports on a daily
basis. The kernel mode caching results were always the most interesting. The common
characteristic was network saturation by requests/responses and IIS running at about five
percent CPU utilization. It was amazing! There are certainly other reasons for using IIS
6.0, but kernel mode caching is an obvious one.

Tip 9—Use Gzip Compression


While not necessarily a server performance tip (since you might see CPU utilization go
up), using gzip compression can decrease the number of bytes sent by your server. This
gives the perception of faster pages and also cuts down on bandwidth usage. Depending
on the data sent, how well it can be compressed, and whether the client browsers support
it (IIS will only send gzip compressed content to clients that support gzip compression,
such as Internet Explorer 6.0 and Firefox), your server can serve more requests per
second. In fact, just about any time you can decrease the amount of data returned, you
will increase requests per second.
The good news is that gzip compression is built into IIS 6.0 and is much better than the
gzip compression used in IIS 5.0. Unfortunately, when attempting to turn on gzip
compression in IIS 6.0, you may not be able to locate the setting on the properties dialog
in IIS. The IIS team built awesome gzip capabilities into the server, but neglected to
include an administrative UI for enabling it. To enable gzip compression, you have to
spelunk into the innards of the XML configuration settings of IIS 6.0 (which isn't for the
faint of heart). By the way, the credit goes to Scott Forsyth of OrcsWeb who helped me
figure this out for the www.asp.net severs hosted by OrcsWeb.
Rather than include the procedure in this article, just read the article by Brad Wilson at
IIS6 Compression. There's also a Knowledge Base article on enabling compression for
ASPX, available at Enable ASPX Compression in IIS. It should be noted, however, that
dynamic compression and kernel caching are mutually exclusive on IIS 6.0 due to some
implementation details.

Tip 10—Server Control View State


View state is a fancy name for ASP.NET storing some state data in a hidden input field
inside the generated page. When the page is posted back to the server, the server can
parse, validate, and apply this view state data back to the page's tree of controls. View
state is a very powerful capability since it allows state to be persisted with the client and
it requires no cookies or server memory to save this state. Many ASP.NET server
controls use view state to persist settings made during interactions with elements on the
page, for example, saving the current page that is being displayed when paging through
data.
There are a number of drawbacks to the use of view state, however. First of all, it
increases the total payload of the page both when served and when requested. There is
also an additional overhead incurred when serializing or deserializing view state data that
is posted back to the server. Lastly, view state increases the memory allocations on the
server.
Several server controls, the most well known of which is the DataGrid, tend to make
excessive use of view state, even in cases where it is not needed. The default behavior of
the ViewState property is enabled, but if you don't need it, you can turn it off at the
control or page level. Within a control, you simply set the EnableViewState property to
false, or you can set it globally within the page using this setting:
<%@ Page EnableViewState="false" %>
If you are not doing postbacks in a page or are always regenerating the controls on a page
on each request, you should disable view state at the page level.

Connection Pooling in ADO.NET


Why go for Connection Pooling?

Establishing connection to a database is cumbersome and resource burning, most


important job in the applications, sometimes it might be slow. Most of the applications
need to execute any query on the database server, a connection need to be established.
Knowing about the Connection Pooling concepts and tips will definitely improves the
performance while connecting to the database and the same time solves the requirement.

Connection Pooling at a glance?

Connection Pooling is the ability to reuse the database connection for more than one user.
That connection might be SQL, OLEDB, ORACLE or whatever. This way of organizing
connections in a smarter manner improves performance as the applications do not need to
open and close the connection multiple times.

All of us know that we declare the connection string in web.config as follows in .NET
Application and make use of this in code behind while connecting to databases.

<connectionStrings>

<add name="sqlConnectionString" connectionString="Data


Source=vhimabindu;Initial Catalog=DNN;password=himavejella;Integrated
Security=True; Pooling=true; Max pool size=200; Min poolsize=0" />

</connectionStrings>

When the connection is closed or disposed in ADO.NET, it is returned to the connection


pool and remains idle for until a request for a new connection comes in. If none comes in
within this period, the connection to the backend is closed and the connection instance is
removed from the Connection Pool. If all the connections are in the pool are busy then
new connection waits in the queue for the existing connections to be released .We can set
max connections, connection Pool size, Connection Time out etc settings in the
web.config.
The following key value pairs explain the connection pooling settings.

• Connection Lifetime - The time of Connection Creation will be compared to the


current time. If this period exceeds the Connection Lifetime value that is set, then
object pooler destroys the connection. The default value is 0; this will give the
maximum timeout for connection.
• Connection Reset - To reset the connection after it was take out from the
Connection pool. The default value is true.
• Max pool size - Maximum number of connections allowed within the Connection
pool. The value is 100 by default.
• Min pool size - Minimum number of connections allowed within the Connection
pool. The value is 0 by default.
• Pooling - To set the connection Pooling if it is true, the connection is drawn from
the pool or created if no connection available from the pool. The value is true by
default.
• Connection Timeout - Maximum Time (in secs) to wait for a free connection
from the pool. The value is 15 by default.
• Incr Pool Size - Controls the number of connections which are established, when
all the connections are used. The value is 5 by default
• Decr Pool Size - Controls the number of connections which are closed when most
of the established connections are unused. The value is 1 by default

Points to Ponder

• Disabling the connection pooling, infers that the connection object that is created
by the user will not be re-used to any other user.
• A Connection pool will be created when Open() method of connection object is
called. If the same application is using multiple Connection Strings (say more
than one) then multiple connection pools will be created corresponding to each
connection string.
• Connection Pooling is applied in ADO.Net by default.
• Connections that are not explicitly closed are not added or returned to the pool.
Hence The Close() or Dispose() method of Connection need to be called to close
the connection.
• A Connection Pool is freed from the memory when the last connection to the
database is closed.
• Connection Pool’s life time is ended as soon as the application domain is
unloaded. For example at any time when IISRESET runs the Connection Pool
gets destroyed
• Connection Pools cannot be shared across application domains.

The best practice Code

The below code is the best practice that is recommended to use.

Try
{
SqlConnection _sqlConnection = new SqlConnection();
_sqlConnection.ConnectionString =
ConfigurationManager.ConnectionStrings["sqlConnectionString"].ToString();
if (_sqlConnection.State = ConnectionState.Closed)
_sqlConnection.Open();
/*Do some Operations … */}
catch (Exception ex)
{ /*Do something */
}
finally
{ if (_sqlConnection.State != ConnectionState.Closed)
_sqlConnection.Close();
}

Connection Pooling improves the performance of the data driven B2B applications as we
save some time in reusing the existing active database connections. I will be explaining it
in more detail in my next article.

1. What is Loosely Coupling in Object Oriented Programming or Software Design?


System should have as many dependencies as is needed to do their job - and the
dependencies should be few.

2. What is the advantage of Loosely Coupling?


Loose Coupling helps in reusability, easier maintainability, and allows providing "mock"
objects in expensive services as opposed to creating new objects.

3. What is a Concrete Object?


A concrete object is any object created with the keyword new.

4. What is Dependency Injection (DI) in Object Oriented Programming (OOP)?


This is also known as “Inversion of Control" (IoC). It refers to the process of supplying
an external dependency in order to reduce more dependencies to a software component.
This is implemented to achieve loosely coupling. Object's dependencies should be on
interfaces but not on concrete objects.

5. What are the term SOLID stands in OOPs? Explain about it?
SOLID stands for Single Responsibility Open Closed Liskov Substitution Interface
Segregation Dependency Inversion .
SOLID Principles of Object-Oriented Design, as introduced by Robert C Martin.
Single Responsibility Principle
A class (or method) should only have one reason to change.
Open Closed Principle
Extending a class shouldn't require modification of that class.
Liskov Substitution Principle
Derived classes must be substitutable for their base classes.
Interface Segregation Principle
Make fine grained interfaces that are client specific.
Dependency Inversion Principle
Program to the interface, not the implementation.
6. What is Single Responsibility Principle of a class?
There should never be more than one reason for a class to change. The classes should
exist for one purpose only.

7. What are open closed principles of class?


Open Close Principle strictly says that the Software objects like classes, modules and
functions should be open for extension but closed for modifications. The design and
writing of the code should be done in a way such that new functionality should be added
with minimum changes in the existing code. In other words the design should be done in
a way to allow the adding of new functionality as new classes, keeping as much as
possible existing code unchanged.

8. What is Liskov Substitution Principle?


Likov's Substitution Principle states that if a program module is using a Base class, then
the reference to the Base class can be replaced with a Derived class without affecting the
functionality of the program module. In other words derived types must be completely
substitutable for their base types. For ex: If a person knows how to drive a car then he
should be able to drive any type of car.

9. What is Interface Segregation Principle?


The Interface Segregation Principle states that clients should not be forced to
implement interfaces they don't use. Instead of one fat interface many small interfaces are
preferred based on groups of methods, each one serving one submodule.

10. What is Dependency Inversion Principle?


According to this principle the way of designing a class structure is to start from high
level modules to the low level modules: High Level Classes --> Abstraction Layer -->
Low Level Classes
• High-level modules should not depend on low-level modules. Both should depend
on abstractions.
• Abstractions should not depend on details. Details should depend on abstractions.

You might also like