Introduction to OOP in C#: Classes - Page 1
       by kirupa  |  5 January 2007

In the real world, you categorize and sub-categorize your environment based on the objects that can be found in it. For example, you have a chair which can be categorized as furniture. Your refrigerator can be categorized as an appliance. There are many such examples where a specific object is classified by a more general category. 

When it comes to writing code, you can represent things as objects also. This style of programming is known object oriented programming (OOP) where we extend our idea of objects from the real world and represent them using code.

On the Menu
In this tutorial, I will provide you with an introduction to OOP by covering classes in C# and some of the interesting things to be on the lookout out for. Since this will be a long (but fun!) tutorial, I have divided the content into the following smaller sections for easier digestion:

  1. Introducing Classes and Objects
  2. Setting Up your Project
  3. Defining a Class
    1. Public and Private Modifiers
    2. Constructors
  4. Methods (Functions)
    1. Instance Methods
    2. Static Methods
  5. AutoComplete in Visual Studio
  6. Conclusion

Introducing Classes and Objects
Let's step away from the world of computers and think about how objects and classes relate to the real world, and since I am a big fan of outer space, I will use an intergalactic theme throughout this tutorial.

In our solar system, you have planets. For something to be a planet, it must meet the following criteria:

  • Orbits around the sun.
  • Has enough mass to maintain a stable shape.
  • Does not shine with its own light.

There are a few more criteria, but you get the basic idea of what characteristics something must possess in order to be considered a planet. With your definition of planet set, you can then associate real world things that would fall under the planet category. As you know, there are quite a number of planets in our solar system - Earth being a particularly important one!

Ok, now let's link the planet example to our goal of understanding classes. A class would be similar to the definition of planets, for classes set the guidelines and specify the characteristics necessary for something to be associated with it. The individual planets themselves - Mercury, Mars, Earth, etc. - would be considered objects or instances because they inherit their unique characteristics from a class called planet. Another way of saying it would be that these objects are of type planet.

To recap, in order for something to be a planet, it must posses all the characteristics as defined by your Planet category. In order for an object to be part of a class, the object must incorporate all of the characteristics specified as being associated with the class. I think you now have a good idea of what classes and objects are. There are more nitpicky details, but for now, we'll play it by ear and learn those details along the way.


Setting Up your Project
In this tutorial, you will be writing some code to put into practice what you read. While you can use any IDE, I will provide instructions for what most of you probably use for your .NET development, Visual Studio 2005:

  1. Launch Visual Studio. Once launched, go to File | New | Project:

  1. The New Project window should appear. From this window, select Console Application under the Templates view:

  1. Glance your eyes down a few inches and enter ClassTutorial as the name for your project:

  1. Press OK to accept the changes.

You now have a empty project with a Main method that you can use to test your code in.

Defining a Class
Let's now take a look at defining a class. Copy and paste this code directly above your class Program definition in the code view:

class Planet
{
public int radius;
public int gravity;
private string name;
}

For clarification on where exactly to paste the code, my code view looks like the following after pasting the above code:

using System;
using System.Text;
 
namespace ClassTutorial
{
class Planet
{
public int radius;
public int gravity;
private string name;
}
 
class Program
{
static void Main(string[] args)
{
 
}
}
}

Let's get back the Planet class you copied and pasted earlier. In the first line I use the class keyword followed by the name of our class. It is good programming convention to capitalize the first letter of a class.

The body of our class contains three fields (variables): radius, gravity, name. Any object that is based on the planet class will have a copy of these three variables and any values you assign to these variables.

If you wanted to use our Planet class, all you need to do is create an object of type Planet:

Planet earth = new Planet();
earth.gravity = 9.81;
earth.radius = 6378;

Notice that I use the new keyword to initialize earth to refer to an object of type Planet. With our earth object now created, we can assign values to the variables radius and gravity. Notice that when you attempt to assign a value to the name field, you receive an error. The reason is that name is a private field whereas radius and gravity are both public fields.

Public and Private Modifiers
A public field is one in which you can access the values from outside of the class. For example, an object can access something marked as public as you saw when we assigned values to our gravity and radius fields.

When something is marked private, though, that means only code stored within our class can access it. Our earth object is beyond the reach of our private name field, so we couldn't access the name field and assign it a name like we may have wanted.

Constructors
When you create an object, you use something called a constructor. A constructor is usually a method (function) whose name is same as that of our class, and it often takes in arguments that help initialize any fields that the object would need.

In our Planet class, we do not have a constructor. When you do not create a constructor, a default constructor is provided for you. That is why when you typed Planet earth = new Planet(), your compiler did not give you an error.

So, let's modify our Planet class by creating a constructor:

class Planet
{
public int radius;
public double gravity;
private string name;
 
// A Constructor
public Planet()
{
Console.WriteLine("Constructor called!");
}
}

In the above code example, notice that I created a simple constructor called Planet(). This constructor does pretty much the same thing as our automatically generated default constructor, but one difference is that in my version, I output "Constructor called!" to the console everytime a new Planet object is created.

A default constructor is not fun. After all, a primary reason for using a constructor is so that your objects can have their fields initialized when they. A default constructor doesn't help with that unless you have no fields that need initializing. Since we have three fields that need to be initialized, let's modify our Planet constructor again:

class Planet
{
public int radius;
public double gravity;
private string name;
 
// A Constructor
public Planet(int r, int g, string n)
{
radius = r;
gravity = g;
name = n;
}
}

Notice that our constructor takes in three arguments this time. In the body of the constructor, I assign our radius, gravity, and name fields the value of the incoming r, g, and n arguments.

To use the above constructor, you will use the following line:

Planet earth = new Planet(6378, 9.81, "Earth");

Notice that our earlier no-argument new Planet() constructor will no longer work. Since your constructor now takes in three arguments, you must provide the three arguments needed or else you won't be able to run your program.

But notice that, since you pass in the values you want your fields to have, you no longer need to initialize them separately. If you want to know what values your earth object's radius and gravity variables possess, all you have to is type Console.WriteLine(earth.radius + ", " + earth.gravity);

Despite our constructor simplifying how fields are initialized, we still cannot access our private name field outside of the Planet class. Notice, though, that our constructor was able to assign the value "Earth" to our name field because the constructor is inside the class itself. Hopefully before the next section is over, we will figure out a way to access the data stored by our name variable!

Methods (Functions)
Up until now, our Planet class only had fields and a constructor. They are great for simply creating your object and initializing fields, but beyond that, they cannot help you. In order to have your class do more interesting things, you will need to use methods. You may see methods referred to by name as functions also, but in order to be consistent, I will only be using the word method.

In a nutshell, a method is a block of code that does something specific. It has a name and various tags (properties) that describe its behavior. More importantly, methods also have the ability to return data back to whoever called it. For example, you probably have been using a method called Main to test your programs:

static void Main(string[] args)
{
Planet earth = new Planet(6378, 9.81, "Earth");
 
Console.WriteLine("Earth's radius is: " + earth.radius);
}

To best describe the individual parts that make up a method, I will use the diagram:

Your method declaration follows the template shown in the above image. The following list explains what each part means:

  • Access Modifier
    Access modifiers define how easily accessible your method will be, and this will be very important when I explain inheritance. The access modifiers we learned so far are public and private, and the other modifiers, which I will cover on a later date, are protected, static, internal, readonly, volatile, new, and protected internal.
  • Return Type
    The type of an object is basically the class it belongs to. The return-type is then the type of the data you are returning when the method is called. If you set your return type to void, that means that you are not sending any data back. We'll see an example of this in use shortly.
  • Method Name
    This is pretty easy! This is just the name you give your method.
  • Arguments (arg1, arg2,..., arg N)
    Your method can take in values much like how our constructor took in values to assign values to our fields.
  • Body of Method
    Your method's code would go here.

Now that you have a basic idea of what goes into a method, let's look at the first type of method I will cover, Instance Methods.

Instance Methods
Instance methods are methods you call from a object. The best way to explain it is via an example. For the past few pages, we have tried to get data from our name field to display when accessed via our object. Let's use a method to do that right now.

Add the following non-grayed out code to your Planet class:

class Planet
{
public int radius;
public double gravity;
private string name;
 
// A Constructor
public Planet(int r, double g, string n)
{
radius = r;
gravity = g;
name = n;
}
 
//Return the object's name!
public string GetName()
{
return name;
}
}

More specifically, the code you added is shown below:

//Return the object's name!
public string GetName()
{
return name;
}

Let's dissect our GetName() method. Notice that its return type is string, and in the body of our method, we return the name field which is also of type string. The return type of your method must match the return type of the value being returned. Finally, notice that the access modifier of our method is public. Guess what that means?

You'll find out when you add the following code to your Main method:

static void Main(string[] args)
{
Planet earth = new Planet(6378, 9.81, "Earth");
 
Console.WriteLine("Earth's radius is: " + earth.radius);
Console.WriteLine("Earth's name is: " + earth.GetName());
}

Notice that when you run your application by pressing Ctrl + F5, you will see not only the radius being being displayed, but the name is also displayed:

The reason the name is displayed is because while the name field is private, the method that returns the value is public. Our goal was to hide the name field, but not to hide the GetName() method. Since GetName() is within our Planet class definition, returning the private name field is allowed.

Static Methods
The other type of method you can use is called a static method. Unlike instance methods that could only be called from an object (ie: earth.GetName()), static methods can be called by polling the class directly.

Like before, let me first provide an example and then I will discuss the details. Add the following colored lines to your Planet definition:

class Planet
{
public int radius;
public double gravity;
private string name;
private static int count;
 
// A Constructor
public Planet(int r, double g, string n)
{
radius = r;
gravity = g;
name = n;
 
count++;
}
 
//Return the object's name!
public string GetName()
{
return name;
}
 
//Static method returning count of all planets
public static int GetCount()
{
return count;
}
}

The above changes are fairly minor. I first declare a static int field called count. In the constructor, I increment our count field by one by using the ++ operator. Second, I created a static method called GetCount() that returns the value stored by our count field. What I have just written still does not explain what static represents, but if you wait a few more lines, you will find out what it does.

To see what the code you added to the Planet class accomplishes, overwrite your main method with what I have provided below and run your program:

class Program
{
static void Main(string[] args)
{
Planet earth = new Planet(6378, 9.81, "Earth");
Planet saturn = new Planet(60268, 8.96, "Saturn");
 
Console.WriteLine("Total planets so far are: " + Planet.GetCount());
}
}

Notice that when you run your program, your output should be "Total planets so far: 2" That is, after all, the correct answer because we only have two planet objects created  - earth and saturn.

What is interesting is more interesting than the number of planets is how I call the GetCount() method: Planet.GetCount(). Instead of accessing GetCount() from either the earth or saturn objects, I am going straight to the Planet class itself. That outcome is a result of tagging the GetCount() method with the static modifier.

The following diagram should help you get an idea of how static and instance methods/ and fields are shared in our program:

As you can see from the dotted lines in the above image, static variables and methods are shared among all objects. Even though I have two objects called earth and saturn, only one copy of the count field and getCount() method are generated. If you remove the static modifier, you will only be able to access the getCount() method via an object, for example - earth.GetCount(). Also, the data will be localized to just your object as seen by the instance variables and GetName() method in the blue Saturn and Earth boxes.

AutoComplete in Visual Studio
Up until now, I gave you the impression that you had to know beforehand which methods and fields were public or private before attempting to access them. In Visual Studio, the Auto-Complete feature does a good job exposing the public fields that you can access when you simply type the name of your object followed by the a . dot/period:

As you can see from the above image, I am able to see all of the methods and fields that are exposed by the Planet class that I can access. Besides the gravity, radius, and GetName entries in the Auto-Complete box, the rest are part of default methods that all classes automatically have.

Conclusion
If you are familiar with how object-oriented programming (OOP) works in other languages such as Java, much of this tutorial must have been a review for you. If this is your first introduction to OOP, this tutorial covered a lot of ground, and I introduced a lot of terminology that you will encounter in the real world. To best learn this material, play around and create some simple applications. A tutorial can only give you the basic idea of how something works, and its up to you to extend what you learned and apply it in your own programs.

Just a final word before we wrap up. If you have a question and/or want to be part of a friendly, collaborative community of over 220k other developers like yourself, post on the forums for a quick response!

Kirupa's signature!

 




SUPPORTERS:

kirupa.com's fast and reliable hosting provided by Media Temple.