C# concepts

86
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

description

 

Transcript of C# concepts

Page 1: C# concepts

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.

Page 2: C# concepts

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.

Page 3: C# concepts

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.

Page 4: C# concepts

 

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:

Page 5: C# concepts

1. Interface2. Implementation or Behavior3. 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

Page 6: C# concepts

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(){

Page 7: C# concepts

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.

Page 8: C# concepts

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

Page 9: C# concepts

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

OutputName: John L. MalgraineSSN: 444-55-6666Employee 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.

Page 10: C# concepts

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

Page 11: C# concepts

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

Page 12: C# concepts

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

Page 13: C# concepts

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{

Page 14: C# concepts

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

Page 15: C# concepts

Name: John M. TrainerAlias: jtrainerTaxes: $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

Page 16: C# concepts

}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

Page 17: C# concepts

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.

Page 18: C# concepts

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;

Page 19: C# concepts

}}

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

Page 20: C# concepts

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.

Page 21: C# concepts

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

Page 22: C# concepts

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

Page 23: C# concepts

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{

Page 24: C# concepts

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.

Page 25: C# concepts

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

Page 26: C# concepts

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

Page 27: C# concepts

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.

Page 28: C# concepts

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 rootArrayList myArray = new ArrayList();// Create 10000 objects in the heapfor (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.}}

Page 29: C# concepts

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

Page 30: C# concepts

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.

Page 31: C# concepts

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 connectionConsole.WriteLine("In Finalize."); }}

Page 32: C# concepts

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

Page 33: C# concepts

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

Page 34: C# concepts

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

Page 35: C# concepts

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.

Page 36: C# concepts

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.

Page 37: C# concepts

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.

Chapter Objective

OOP's overview Classes and Objects

Page 38: C# concepts

Constructor and Destructor Function Overloading Encapsulation Inheritance Interface Polymorphism

OOP's overview

Object-oriented programming (OOP) is the core ingredient of the .NET framework. OOP is so important that, before embarking on the road to .NET, you must understand its basic principles and terminology to write even a simple program. The fundamental idea behind OOP is to combine into a single unit both data and the methods that operate on that data; such units are called an object. All OOP languages provide mechanisms that help you implement the object-oriented model. They are encapsulation, inheritance, polymorphism and reusability. Let's now take a brief look at these concepts.

Encapsulation

Encapsulation binds together code and the data it manipulates and keeps them both safe from outside interference and misuse. Encapsulation is a protective container that prevents code and data from being accessed by other code defined outside the container.

Inheritance

Inheritance is the process by which one object acquires the properties of another object. A type derives from a base type, taking all the base type members fields and functions. Inheritance is most useful when you need to add functionality to an existing type. For example all .NET classes inherit from the System.Object class, so a class can include new functionality as well as use the existing object's class functions and properties as well.

Polymorphism

Polymorphism is a feature that allows one interface to be used for a general class of action. This concept is often expressed as "one interface, multiple actions". The specific action is determined by the exact nature of circumstances.

Reusability

Once a class has been written, created and debugged, it can be distributed to other programmers for use in their own program. This is called reusability, or in .NET terminology this concept is called a component or a DLL. In OOP, however, inheritance provides an important extension to the idea of reusability. A programmer can use an existing class and without modifying it, add additional features to it.

Simple "Hello World" C# Program

This simple one-class console "Hello world" program demonstrates many fundamental concepts throughout this article and several future articles.

C# code

using System;

Page 39: C# concepts

namespace oops{

    //class definition    public class SimpleHelloWorld    {         //Entry point of the program        static void Main(string[] args)        {            //print Hello world"            Console.WriteLine("Hello World!");        }    }}

So SimpleHelloWorld is the name of the class that contains the Main () method. On line 1 , a using directive indicates to the compiler that this source file refers to classes and constructs declared within the System namespace. Line 6 with the public keyword indicates the program accessibility scope for other applications or components.

At line 7 there appears an opening curly brace ("{") which indicates the beginning of the SimpleHelloWorld class body. Everything belongs to the class, like fields, properties and methods appear in the class body between the opening and closing braces. The purpose of the Main () method is to provide an entry point for application execution.

The static keyword in the Main () method states that this method would be executed without instantiating the class.

Compiling the Program

You can compile a C# program into either an assembly or a module. If the program has one class that contains a Main () method then it can be compiled directly into an assembly. This file has an ".exe" extension. A program with no Main() method can be compiled into a module as in the following:

csc /target:module "program name"

You can then compile this program by F9 or by simply running the C# command line compiler (csc.exe) against the source file as the following:

csc oops.cs

Classes and Objects

Classes are special kinds of templates from which you can create objects. Each object contains data and methods to manipulate and access that data. The class defines the data and the functionality that each object of that class can contain.

Page 40: C# concepts

A class declaration consists of a class header and body. The class header includes attributes, modifiers, and the class keyword. The class body encapsulates the members of the class, that are the data members and member functions. The syntax of a class declaration is as follows:

Attributes accessibility modifiers class identifier: baselist { body }

Attributes provide additional context to a class, like adjectives; for example the Serializable attribute. Accessibility is the visibility of the class. The default accessibility of a class is internal. Private is the default accessibility of class members. The following table lists the accessibility keywords;

Keyword Descriptionpublic Public class is visible in the current and referencing assembly.private Visible inside current class.protected Visible inside current and derived class.Internal Visible inside containing assembly.Internal protected Visible inside containing assembly and descendent of the current class.

Modifiers refine the declaration of a class. The list of all modifiers defined in the table are as follows;

Modifier Descriptionsealed Class can't be inherited by a derived class.static Class contains only static members.unsafe The class that has some unsafe construct likes pointers.Abstract The instance of the class is not created if the Class is abstract.

The baselist is the inherited class. By default, classes inherit from the System.Object type. A class can inherit and implement multiple interfaces but doesn't support multiple inheritances.

Step-by-step Tutorial for Creating a Class

1. Open Visual Studio 2010 from start menu.2. Go to "File" > "New" > "Project...", select "Console Application" in the right pane and

provide the name "oops" for the project.3. Then in the Solution Explorer, you will notice some files that are automatically

created as:

Page 41: C# concepts

 4. You can also write your own code in the default program.cs file that is created but it

is a good programming practice to create a new class.5. For adding a new class, right-click over the project name (oops) in the Solution

Explorer, then click "Add" > "Class". Give the name to the class "customer" as in the following;

 6. When you open the customer.cs class. you will find some default-generated code as

in the following;

C# code

Page 42: C# concepts

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

namespace oops{    class customer    {    }}

Note: the C# console application project must require a single entry point Main () function that is already generated in the program class. For example if you add a new customer class and want to define one or more Main () entry points here then .NET will throw an error of multiple entry points. So it is advisable to delete or exclude the program.cs file from the solution.

So here in this example the customer class defines fields such as CustID, Name and Address to hold information about a particular customer. It might also define some functionality that acts upon the data stored in these fields.

C# code

using System;

namespace oops{    class customer    {        // Member Variables        public int CustID;        public string Name;        public string Address;

        //constuctor for initializing fields        customer()        {            CustID=1101;            Name="Tom";            Address="USA";        }

        //method for displaying customer records (functionality)        public void displayData()        {            Console.WriteLine("Customer="+CustID);            Console.WriteLine("Name="+Name);            Console.WriteLine("Address="+Address);          }       // Code for entry point

Page 43: C# concepts

    }}

At line 9, we are defining a constructor of the customer class for initializing the class member fields. The constructor is a special function that is automatically called when the customer class object is created (instantiated). And at line 11 we are printing these fields to the console by creating a user defined method displayData().

You can then instantiate an object of this class to represent one specific customer, set the field value for that instance and use its functionality, as in:

C# code

class customer    {        // class members code

         //Entry point        static void Main(string[] args)        {            // object instantiation            customer obj = new customer();

            //Method calling            obj.displayData();

             //fields calling            Console.WriteLine(obj.CustID);            Console.WriteLine(obj.Name);               Console.WriteLine(obj.Address);           }    }

Here you use the keyword new to declare the customer class instance. This keyword creates the object and initializes it. When you create an object of the customer class, the .NET framework IDE provides a special feature called Intellisense that provides access to all the class member fields and functions automatically. This feature is invoke when the "." Operator is put right after the object, as in the following;

Page 44: C# concepts

Image 1.1 Intellisense feature

Normally, as the program grows in size and the code becomes more complex, the Intellisense feature increases the convenience for the programmer by showing all member fields, properties and functions.

Multiple Class Declaration

Sometimes circumstances require multiple classes to be declared in a single namespace. So in that case it is not mandatory to add a separate class to the solution, instead you can attach the new class into the existing program.cs or another one as in the following;

C# code

using System;

namespace oops{    class Program    {

        public void MainFunction()        {          Console.WriteLine("Main class");        }        static void Main(string[] args)        {            //main class instance

Page 45: C# concepts

            Program obj = new Program();            obj.MainFunction();

            //other class instace            demo dObj=new demo();            dObj.addition();         }    }

    class demo    {        int x = 10;        int y = 20;        int z;

        public void addition()        {            z = x + y;            Console.WriteLine("other class in Namespace");            Console.WriteLine(z);          }    }}

Here in this example, we are creating an extra class "demo" in the program.cs file at line 12 and finally we are instantiating the demo class with the program class inside the Main() entry in lines 6 to 11. So it doesn't matter how many classes we are defining in a single assembly.

Partial classes

Typically, a class will reside entirely in a single file. However, in situations where multiple developers need access to the same class, then having the class in multiple files can be beneficial. The partial keywords allow a class to span multiple source files. When compiled, the elements of the partial types are combined into a single assembly.

There are some rules for defining a partial class as in the following;

A partial type must have the same accessibility.

Each partial type is preceded with the "partial" keyword.

If the partial type is sealed or abstract then the entire class will be sealed and abstract.

In the following example we are adding two files, partialPart1.cs and partialPart2.cs, and declare a partial class, partialclassDemo, in both classes.

partialPart1.cs

Page 46: C# concepts

using System;

namespace oops{    public partial class partialclassDemo    {        public void method1()        {            Console.WriteLine("method from part1 class");          }    }}

partialPart2.cs

using System;

namespace oops{    public partial class partialclassDemo    {        public void method2()        {            Console.WriteLine("method from part2 class");        }    }}

And finally we are creating an instance of the partialclassDemo in the program.cs file as the following:

Program.cs

using System;

namespace oops{    class Program    {        static void Main(string[] args)        {            //partial class instance            partialclassDemo obj = new partialclassDemo();            obj.method1();            obj.method2();         }    }}

Page 47: C# concepts

Static classes

A static class is declared using the "static" keyword. If the class is declared as static then the compiler never creates an instance of the class. All the member fields, properties and functions must be declared as static and they are accessed by the class name directly not by a class instance object.

C# code

using System;

namespace oops{    static class staticDemo    {        //static fields        static int x = 10, y;

        //static method        static void calcute()        {            y = x * x;            Console.WriteLine(y);          }        static void Main(string[] args)        {            //function calling directly            staticDemo.calcute();         }    }}

Creating and accessing Class Component Library

.NET provides the capability of creating libraries (components) of a base application rather than an executable (".exe"). Instead the library project's final build version will be ".DLL" that can be referenced from other outside applications to expose its entire functionality.

Step-by-step tutorial

1. First create a class library based application as:

Page 48: C# concepts

2. Then we are implementing a math class library that is responsible of calculating square root and the addition of two numbers as:

using System;

namespace LibraryUtil{    public class MathLib    {        public MathLib() { }

        public void calculareSum(int x, int y)        {            int z = x + y;            Console.WriteLine(z);          }

        public void calculareSqrt(double x)        {            double z = Math.Sqrt(x);              Console.WriteLine(z);        }    }}

3. Build this code and you will notice that a DLL file was created, not an executable, in the root directory of the application (path = D:\temp\LibraryUtil\LibraryUtil\bin\Debug\ LibraryUtil.dll).

Page 49: C# concepts

4. Now create another console based application where you utilize all the class library's functionality.5. Then you have to add the class library dll file reference to access the declared class in the library dll. (Right-click on the Reference then "Add reference" then select the path of the dll file.)6. When you add the class library reference then you will notice in the Solution Explorer that a new LibraryUtil is added as in the following;

7. Now add the namespace of the class library file in the console application and create the instance of the class declared in the library as in the following;

using System;using LibraryUtil; // add library namespacenamespace oops{    public class LibraryClass    {        static void Main()        {            //library class instance            MathLib obj = new MathLib();

            //method populate            obj.calculareSum(2, 5);            obj.calculareSqrt(25);        }    }}

8. Finally run the application.

Page 50: C# concepts

Constructor and Destructor

A constructor is a specialized function that is used to initialize fields. A constructor has the same name as the class. Instance constructors are invoked with the new operator and can't be called in the same manner as other member functions. There are some important rules pertaining to constructors as in the following;

Classes with no constructor have an implicit constructor called the default constructor, that is parameterless. The default constructor assigns default values to fields.

A public constructor allows an object to be created in the current assembly or referencing assembly.

Only the extern modifier is permitted on the constructor.

A constructor returns void but does not have an explicitly declared return type.

A constructor can have zero or more parameters.

Classes can have multiple constructors in the form of default, parameter or both.

The following example shows one constructor for a customer class.

C# code 

using System;namespace oops{    class customer    {        // Member Variables        public string Name;

        //constuctor for initializing fields        public customer(string fname, string lname)        {            Name= fname +" "+ lname;        }         //method for displaying customer records        public void AppendData()        {            Console.WriteLine(Name);        }         //Entry point        static void Main(string[] args)        {            // object instantiation            customer obj = new customer("Barack", "Obama");

Page 51: C# concepts

            //Method calling            obj.AppendData();        }    }}

Note: The moment a new statement is executed, the default constructor is called.

Static Constructor

A constructor can be static. You create a static constructor to initialize static fields. Static constructors are not called explicitly with the new statement. They are called when the class is first referenced. There are some limitations of the static constructor as in the following;

Static constructors are parameterless.

Static constructors can't be overloaded.

There is no accessibility specified for Static constructors.

In the following example the customer class has a static constructor that initializes the static field and this constructor is called when the class is referenced in the Main () at line 26 as in the following:

C# code

using System;namespace oops{    class customer    {        // Member Variables        static private int x;

        //constuctor for static initializing fields        static customer()        {            x = 10;        }        //method for get  static field        static public void getData()        {            Console.WriteLine(x);        }         //Entry point        static void Main(string[] args)        {           //static Method calling            customer.getData();        }

Page 52: C# concepts

    }}

Destructors

The purpose of the destructor method is to remove unused objects and resources. Destructors are not called directly in the source code but during garbage collection. Garbage collection is nondeterministic. A destructor is invoked at an undetermined moment. More precisely a programmer can't control its execution; rather it is called by the Finalize () method. Like a constructor, the destructor has the same name as the class except a destructor is prefixed with a tilde (~). There are some limitations of destructors as in the following;

Destructors are parameterless.

A Destructor can't be overloaded.

Destructors are not inherited.

Destructors can cause performance and efficiency implications.

The following implements a destructor and dispose method. First of all we are initializing the fields via constructor, doing some calculations on that data and displaying it to the console. But at line 9 we are implementing the destructor that is calling a Dispose() method to release all the resources.

using System;namespace oops{    class customer    {        // Member Variables        public int x, y;        //constuctor for  initializing fields        customer()        {            Console.WriteLine("Fields inititalized");            x = 10;        }        //method for get field        public void getData()        {            y = x * x;            Console.WriteLine(y);        }        //method to release resource explicitly        public void Dispose()        {            Console.WriteLine("Fields cleaned");            x = 0;

Page 53: C# concepts

            y = 0;        }        //destructor        ~customer()        {            Dispose();        }         //Entry point        static void Main(string[] args)        {            //instance created            customer obj = new customer();

            obj.getData();

        }    }}

At line 12 when the instance is created, fields are initialized but it is not necessary that at the same time the destructor is also called. Its calling is dependent on garbage collection. If you want to see the destructor being called into action then put a breakpoint (by F9) at line 10 and compile the application. The CLR indicates its execution at the end of the program by highlighting line 10 using the yellow color.

Function Overloading

Function overloading allows multiple implementations of the same function in a class. Overloaded methods share the same name but have a unique signature. The number of parameters, types of parameters or both must be different. A function can't be overloaded on the basis of a different return type alone.

using System;namespace oops{    class funOverload    {        public string name;

        //overloaded functions        public void setName(string last)        {            name = last;        }

        public void setName(string first, string last)        {            name = first + "" + last;        }

Page 54: C# concepts

        public void setName(string first, string middle, string last)        {            name = first + "" + middle + "" + last;        }

        //Entry point        static void Main(string[] args)        {            funOverload obj = new funOverload();

            obj.setName("barack");            obj.setName("barack "," obama ");            obj.setName("barack ","hussian","obama");         }    }}

At lines 3, 4 and 5 we are defining three methods with the same name but with different parameters. In the Main (), the moment you create an instance of the class and call the functions setName() via obj at lines 7, 8 and 9 then intellisense will show three signatures automatically.

Encapsulation

Encapsulation is the mechanism that binds together the code and the data it manipulates, and keeps both safe from outside interference and misuse. In OOP, code and data may be combined in such a way that a self-contained box is created. When code and data are linked together in this way, an object is created and encapsulation exists.

Within an object, code, data or both may be private or public to that object. Private code is known to and accessible only by another part of the object, that is private code or data may not be accessible by a piece of the program that exists outside the object. When the code and data is public, other portions of your program may access it even though it is defined within an object.

C# code

using System;namespace oops{    class Encapsulation    {        /// <summary>        /// Every member Variable and Function of the class are bind        /// with the Encapsulation class object only and safe with         /// the outside inference        /// </summary>

Page 55: C# concepts

        // Encapsulation Begin        int x;

        //class constructor        public Encapsulation(int iX)        {            this.x = iX;        }

        //calculating the square        public void MySquare()        {            int Calc = x * x;            Console.WriteLine(Calc);        }       

        // End of Encapsulation

         //Entry point        static void Main(string[] args)        {            //instance created            customer obj = new customer(20);                       obj. MySquare();                    }

    }}

Inheritance

Inheritance is the process by which one object can acquire the properties of another object. Inheritance is a "is a kind of" relationship and it supports the concept of classification in which an object needs only define those qualities that make it unique within the class. Inheritance involves a base class and a derived class. The derived class inherits from the base class and also can override inherited members as well as add new members to extend the base class.

A base type represents the generalization, whereas a derived type represents a specification of an instance. Such as Employees that can have diverse types, such as hourly, salaried and temporary so in that case Employees is the general base class and hourly, salaried and temporary employee are specialized derived classes.

Classes can inherit from a single class and one or more interfaces. When inheriting from a class, the derived class inherits the members including the code of the base class. The important point to remember is that Constructors and Destructors are not inherited from the base class.

The syntax of inheritance is as in the following;Class derivedClass : baseClass, Iterface1, Interface2 { body }

Page 56: C# concepts

For example we are defining two classes, Father and Child. You notice at line 7, we are implementing inheritance by using a colon (:); at this moment all the properties belonging to the Father Class is accessible to the Child class automatically.

C# code

using System;namespace oops{    //Base Class    public class Father    {        public void FatherMethod()        {            Console.WriteLine("this property belong to Father");        }    }     //Derived class    public class Child : Father    {        public void ChildMethod()        {            Console.WriteLine("this property belong to Child");        }    }    class Inheritance    {        //Entry point

Page 57: C# concepts

        static void Main(string[] args)        {

            Father fObj = new Father();            fObj.FatherMethod();             //Here Child object can access both class methods            Child cObj = new Child();            cObj.FatherMethod();            cObj.ChildMethod();          }    }}

At line 11 , the Intellisense only shows the Father class functions but at line 15 to 16 the Child class object is able to access both class methods as in the following.

We can create a class in the VB.Net language or another .NET supported language and can inherit them in a C# .Net class and vice versa. But a class developed in C++ or other unmanaged environment can't be inherited in .NET.Note: Cross-language and multiple inheritance is not supported by .NET.

Accessibility

Accessibility sets the visibility of the member to outside assemblies or derived types. The following table describes member accessibility;

Modifiers Outside Assembly Derived Classprivate No Nopublic Yes Yesprotected No Nointernal Yes ( this assembly only) Yes ( this assembly only)internal protected Yes( this assembly only) Yes

Constructor in Inheritance

Constructors in a base class are not inherited in a derived class. A derived class has a base portion and derived portion. The base portion initializes the base portion, and the constructor of the derived class initializes the derived portion.The following is the syntax of a constructor in inheritance;

Accessibility modifier classname(parameterlist1) : base(parameterlist2) { body }

So the base keyword refers to the base class constructor, while parameterlist2 determines which overloaded base class constructor is called.

In the following example, the Child class's constructor calls the single-argument constructor of the base Father class;

C# code

Page 58: C# concepts

using System;namespace oops{    //Base Class    public class Father    {

        //constructor        public Father()        {            Console.WriteLine("Father class constructor");        }

        public void FatherMethod()        {            Console.WriteLine("this property belong to Father");        }    }

    //Derived class    public class Child : Father    {        public Child()            : base()        {            Console.WriteLine("child class constructor");        }        public void ChildMethod()        {            Console.WriteLine("this property belong to Child");        }    }    class Inheritance    {        //Entry point        static void Main(string[] args)        {            //Here Child object can access both class methods            Child cObj = new Child();            cObj.FatherMethod();            cObj.ChildMethod();            Console.ReadKey();        }    }}

At line 4, we are defining a base Father Class constructor and in the derived class Child, at line 8 we are initializing it explicitly via base keyword. If we pass any parameter in the base class constructor then we have to provide them in the base block of the child class

Page 59: C# concepts

constructor.

Virtual Methods

By declaring a base class function as virtual, you allow the function to be overridden in any derived class. The idea behind a virtual function is to redefine the implementation of the base class method in the derived class as required. If a method is virtual in the base class then we have to provide the override keyword in the derived class. Neither member fields nor static functions can be declared as virtual.

C# code

using System;namespace oops{    class myBase    {        //virtual function        public virtual void VirtualMethod()        {            Console.WriteLine("virtual method defined in the base class");        }    }

    class myDerived : myBase     {        // redifing the implementation of base class method        public override void VirtualMethod()        {            Console.WriteLine("virtual method defined in the Derive class");        }    }    class virtualClass    {        static void Main(string[] args)        {            // class instance            new myDerived().VirtualMethod();            Console.ReadKey();          }    }}

Hiding Methods

If a method with the same signature is declared in both base and derived classes, but the methods are not declared as virtual and overriden respectively, then the derived class version is said to hide the base class version. In most cases, you would want to override methods rather than hide them. Otherwise .NET automatically generates a warning.

Page 60: C# concepts

In the following example, we are defining a VirutalMethod() in the myBase class but not overriding it in the derived class, so in that case the compiler will generate a warning. The compiler will assume that you are hiding the base class method. So to overcome that problem, if you prefix the new keyword in the derived class method then the compiler will prefer the most derived version method. You can still access the base class method in the derived class by using the base keyword.

C# code

using System;namespace oops{    class myBase    {        //virtual function        public virtual void VirtualMethod()        {            Console.WriteLine("virtual method defined in the base class");        }    }

    class myDerived : myBase     {        // hiding the implementation of base class method        public new void VirtualMethod()        {            Console.WriteLine("virtual method defined in the Derive class");

            //still access the base class method            base.VirtualMethod();        }    }    class virtualClass    {        static void Main(string[] args)        {            // class instance            new myDerived().VirtualMethod();            Console.ReadKey();          }    }}

Abstract Classes

C# allows both classes and functions to be declared abstract using the abstract keyword. You can't create an instance of an abstract class. An abstract member has a signature but no function body and they must be overridden in any non-abstract derived class. Abstract classes exist primarily for inheritance. Member functions, properties and indexers can be abstract. A class with one or more abstract members must be abstract as well. Static members can't be abstract.

Page 61: C# concepts

In this example, we are declaring an abstract class Employess with a method displayData() that does not have an implementation. Then we are implementing the displayData() body in the derived class. One point to be noted here is that we have to prefixe the abstract method with the override keyword in the derived class.

C# code

using System;namespace oops{    //abstract class    public abstract class Employess    {        //abstract method with no implementation        public abstract void displayData();    }

    //derived class    public class test : Employess    {        //abstract class method implementation        public override void displayData()        {            Console.WriteLine("Abstract class method");        }    }    class abstractClass    {        static void Main(string[] args)        {            // class instance            new test().displayData();            }    }}

Sealed Classes

Sealed classes are the reverse of abstract classes. While abstract classes are inherited and are refined in the derived class, sealed classes cannot be inherited. You can create an instance of a sealed class. A sealed class is used to prevent further refinement through inheritance.

Suppose you are a developer of a class library and some of the classes in the class library are extensible but other classes are not extensible so in that case those classes are marked as sealed.

C# code 

using System;namespace oops{    sealed class SealedClass

Page 62: C# concepts

    {        void myfunv();    }

    public class test : SealedClass //wrong. will give compilation error    {    }}

Interface

An interface is a set of related functions that must be implemented in a derived class. Members of an interface are implicitly public and abstract. Interfaces are similar to abstract classes. First, both types must be inherited; second, you cannot create an instance of either. Although there are several differences as in the following;

An Abstract class can contain some implementations but an interface can't. An Interface can only inherit other interfaces but abstract classes can inherit from

other classes and interfaces. An Abstract class can contain constructors and destructors but an interface can't. An Abstract class contains fields but interfaces don't.

So the question is, which of these to choose? Select interfaces because with an interface, the derived type still can inherit from another type and interfaces are more straightforward than abstract classes.

C# code

using System;namespace oops{    // interface    public interface xyz    {       void methodA();       void methodB();    }

    // interface method implementation    class test : xyz    {        public void methodA()        {            Console.WriteLine("methodA");         }        public void methodB()        {            Console.WriteLine("methodB");         }    }    class interfaceDemo     {        static void Main(string[] args)

Page 63: C# concepts

        {            test obj = new test();            obj.methodA();            obj.methodB();        }    }   }

An interface can be inherited from other interfaces as in the following:

C# code

public interface xyz    {        void methodA();        void methodB();    }

    public interface abc : xyz    {        void methodC();    }

Polymorphism

Polymorphism is the ability to treat the various objects in the same manner. It is one of the significant benefits of inheritance. We can decide the correct call at runtime based on the derived type of the base reference. This is called late binding.

In the following example, instead of having a separate routine for the hrDepart, itDepart and financeDepart classes, we can write a generic algorithm that uses the base type functions. The method LeaderName() declared in the base abstract class is redefined as per our needs in 2 different classes.

C# code

using System;namespace oops{    public abstract class Employee    {        public virtual void LeaderName()        {        }    }

    public class hrDepart : Employee    {        public override void LeaderName()        {            Console.WriteLine("Mr. jone");         }

Page 64: C# concepts

    }    public class itDepart : Employee    {        public override void LeaderName()        {            Console.WriteLine("Mr. Tom");        }    }

    public class financeDepart : Employee    {        public override void LeaderName()        {            Console.WriteLine("Mr. Linus");        }    }

    class PolymorphismDemo    {        static void Main(string[] args)        {            hrDepart obj1 = new hrDepart();            itDepart obj2 = new itDepart();            financeDepart obj3 = new financeDepart();

            obj1.LeaderName();            obj2.LeaderName();            obj3.LeaderName();

            Console.ReadKey();        }    }}

Login to add your contents and source code to this article Article ExtensionsContents added by Zeeshan shan on Feb 06, 2013                                                           OVERIDING EXAMPLE

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

namespace overriding{    abstract class BaseClass    {        public abstract string YourCity();

Page 65: C# concepts

    }

    class DerivedClass : BaseClass    {        public override string YourCity()   //It is mandatory to implement absract method        {            return "London";        }

        private int sum(int a, int b)        {            return a + b;        }    }    class Program    {        static void Main(string[] args)        {            DerivedClass obj = new DerivedClass();            string city = obj.YourCity();            Console.WriteLine(city);            Console.Read();        }    }}

Introduction

In this article, I want to show you the concept of Object-Oriented Programming in C#. Now what are objects and why we’d better write Object-Oriented applications? Good Question! We will cover the following:

What is an object? Creating a class Fields Methods Instantiating your class Access Modifiers Properties

What is an Object

Page 66: C# concepts

In order to understand the meaning of object in our context, you should first understand the concept of classes. Everything in C# .NET is a class. From integer data type to complex encryption and ADO.NET classes. So, for example, when you write the following code, you are actually using FileStream class to declare a variable name fileStream.

Collapse | Copy CodeFileStream fileStream = new FileStream(fileName, FileMode.Create));

So, as you can see, fileStream is a variable of type FileStream which is a class. We call fileStream an object or an instance of type FileStream class rather than a variable because everything is considered as an object. I hope I have made myself clear so far. So, keep in mind that every instance of a class is called an object.

So far we have seen what the difference between a class and an object is. The following is Microsoft’s definition of these terms:

A class definition is like a blueprint that specifies what the type can do. An object is basically a block of memory that has been allocated and configured according to the blueprint. A program may create many objects of the same class. Objects are also called instances.

Every instance of a particular class can access some properties and methods of that class. For example, considering fileStream as an object of type FileStream class, we could write:

Collapse | Copy Codebyte[] dataArray = new byte[100000];for(int i = 0; i < dataArray.Length; i++) { fileStream.WriteByte(dataArray[i]); }

fileStream is calling WriteByte which is a method declared in FileStream class and what it does is not of any interest to us right now. We can also access the properties that are allowed via our instance of a class. Again, assuming fileStream to be an instance of FileStream class, we could write:

Collapse | Copy Codeif (fileStream.CanWrite) { Console.WriteLine("The stream for file is writable.") } else { Console.WriteLine("The stream for file is not writable."); }

I think you have got the idea of classes and objects. However, this was the beginning. I don’t want to go through the classes provided by Microsoft and guide you how to use them but rather I want to show you how you can declare classes of your own. The classes that you create can have

Page 67: C# concepts

methods and properties similarly to those already in the .NET and you can set access policies to those methods and properties which we call members from now on.

Creating a Class

To create a class, you need to add a class file to your project. Right-click on your project inside the solution explorer and click Add and then choose New Item…. On the left side of the new window, navigate to Code template and then click Class from the right-sided pane. Choose a name for your class and click Add. A new file is added to your project. Inside it, you see the declaration of your class as follows. I have named my class Car and it is in the OOPLearning namespace:

Collapse | Copy Codenamespace OOPLearning{ class Car { }}

Fields

To add a field (and a field is simply an object within your class, it could by an integer or any other object) just write the data type of the field and the name:

Collapse | Copy Codeint numberOfDoors;

In the above line of code, I have declared a field of type int which stores the number of the doors that an instance of this class has.

Methods

Methods are the behaviors of your class; the things that an object of that class can do. For example, a class named Dog may have a method named Bark, as dogs bark. And a class named Car can have a method named Accelerate, as cars can accelerate.

We add a method to our class in this manner:

Collapse | Copy Codevoid Accelerate(){ //The logic goes here}

I have eliminated the logic for this method because it’s not of any interest to us right now.

Page 68: C# concepts

Instantiating your Class

Instantiating (creating an instance of a class) is simply the process of declaring an object of a class. You can instantiate a class as follows (I have created a console application and declared an object of type Car in the Main method of the Program.cs file of my project):

Collapse | Copy Codenamespace OOPLearning{ class Program { static void Main(string[] args) { Car myCar = new Car (); } }}

Access Modifiers

As I said, when you create an instance of a class, you can access the members (methods and fields) of that class via your instance. So, this means that I could write the following:

Collapse | Copy CodeCar myCar = new Car ();myCar.numberOfDoors=4;myCar.Accelerate ();

But as you see, the above code has generated an error. Why is that? Because we don’t have access to these members and this is due to their access modifiers which are private. The private keyword is not explicitly written before the Accelerate and numberOfDoors. But since it’s the default access modifier, anything (either method, fields, etc.) that you declare in your class is considered private unless you write one of the following before them:

public protected internal internal protected

We don’t go through these keywords right now. Let’s just change the definition of our class as follows:

Collapse | Copy Codenamespace OOPLearning{ class Car { public int numberOfDoors;

Page 69: C# concepts

public void Accelerate() { //The logic goes here } }}

Now, you can instantiate the Car class and access numberOfDoors and Accelerate:

Collapse | Copy Codeclass Program{ static void Main(string[] args) { Car myCar = new Car (); myCar.numberOfDoors=4; Console.WriteLine (myCar.numberOfDoors); myCar.Accelerate (); }}

Notice that I have set numberOfDoors to the value 4 and then print it out on the console. Simple as that.

Properties

Remember I said fields act as stores for your data. The numberOfDoors is the storage in which we store the number of doors our myCar object has. What if we wanted to control the value passed to this field. For example, the following code would be perfectly valid:

Collapse | Copy Codeclass Program{ static void Main(string[] args) { Car myCar = new Car (); myCar.numberOfDoors=250; Console.WriteLine (myCar.numberOfDoors); }}

But we know that there is no car in the whole world which has 250 doors. We want to make sure the value passed to numberOfDoors is intellectually acceptable. So, we use properties. A property is simply a method that which can help us add logic to when the value of a field is retrieved or set. Look at the following line of code:

Collapse | Copy Codeprivate int numberOfDoors;

public int NumberOfDoors

Page 70: C# concepts

{ get { return numberOfDoors; } set { if ( value >= 2 && value <= 6 ) { numberOfDoors = value; } }

As it’s obvious, we control the value passed to the numberOfDoors and only accept it if it’s between 2 and 6. Now, the property named NumberOfDoors is actually a method which has two parts: get, set. The get part is called whenever we retrieve the value stored in nubmerOfDoors and the set part is called whenever we pass a value to be stored in numberOfDoors. Notice the data type of the property and the field match. Also, pay attention to the syntax. Now, if we write the following code, we see the value 0 in the console as the default value of type integer is:

Collapse | Copy Codeclass Program{ static void Main(string[] args) { Car myCar = new Car (); myCar.NumberOfDoors=250; Console.WriteLine (myCar.NumberOfDoors); Console.ReadKey (); }}

What happened is simply logical. Since the value passed to NumberOfDoors doesn’t conform to our rules (between 2 and 8) the default value of type integer which is zero (which is stored in the field numberOfDoors) is returned. To better understand the concept, let’s change our class to look like this:

Collapse | Copy Codeprivate int numberOfDoors;

get { return numberOfDoors; }set{ if ( value >= 2 && value <= 6 ) { numberOfDoors = value; } else { numberOfDoors = 2; }}

Now run the project again. You see 2 in the console. And that’s because of the else in the set part of NumberOfDoors. If the value passed to the property conforms to our rule, then everything

Page 71: C# concepts

is quite good, otherwise it is set to value 2. There is a lot to properties, but we close our discussion on them here.