Continuing our series about C# programming, in this article we discuss classes, which lie at the heart of any modern Object-Oriented Programming language. Among other things, you will learn some of the ways in which C# is different from C and C++ in this vital area.
In this article we will discuss C# classes and how to create a class in C#. We will also discuss Class Members like fields, constants and static members; I will also discuss the Access Modifiers available in C#.
A class is the core of any modern Object Oriented Programming language such as C#; most of the time, you will be writing classes. If you have a background in C or C++, many class aspects are similar, but some are different. For example, C# doesn't permit functions to exist outside the class declaration like C++; also, C# use the .NET Framework Class Library, so you have access to thousands more functions than the class libraries available to C++.
But the concept of data encapsulation is the same in all the modern OOP languages, so a class in C# contains data (fields for example) and operations that manipulate the data (methods). For example, a class that describes an employee would include fields like firstName, lastName, dateOfBirth, basicSalary and department, and methods that operate on the data, such as CalculateSalary() which calculates the employee's basic salary plus the overtime, for example, and another method like RaiseBasicSalary() that raises the basic salary of the employee.
To create a class, you simply use the keyword "class" followed by the class name:
class Employee {
}
You can precede the class keyword with an access modifier keyword (which we will discuss later in the article):
public class Employee {
}
All of the class members must exist between the curly braces, so you don't have global functions like C++. You can create more than one class definition in one physical file, but it's not a good programming practice; it's better to create each class in one file with the extension .cs
Note that all classes in C# directly or indirectly inherit from one base class, System.Object, and you don't have to explicitly define the inheritance, because the C# compiler enforces it. So the following class:
public class Employee {
}
is the same as:
public class Employee : System.Object {
}
You can add a class to your project using Visual Studio.NET; simply right click the project icon in Solution Explorer window (you can view the Solution Explorer windows using CTRL+ALT+L), then click on Add --> Add Class, and the Add New Item windows will be shown:
Note that you can add a class, Windows Form, Control, Component and many other variations; this is one feature of the Visual Studio.NET tool. For example, when you add Windows Form, VS.NET will create the Form (it's a class too) and generate code that the Form requires.
Modify the name of the class to Employee.cs and click Open. VS.NET will create the file, and generate basic class declaration code:
using System; namespace Company { /// <summary> /// Summary description for Employee. /// </summary> public class Employee { public Employee() { // // TODO: Add constructor logic here // } } }
VS.NET declares the class as public, and creates an empty default constructor along with some comments. These are special kinds of comments that are used for generating documentation -- another feature of VS.NET. For now, delete the documentation and the default constructor, so you will show the Employee class as:
using System; namespace Company { public class Employee { } }
Before we discuss class members you should know that every member must have an access modifier, and if you didn't supply one, C# will consider this member a private member. It's better, however, that you explicitly define it private with the keyword "private." As you can see, there's no semicolon needed after the class declaration, although you can put it there if you're used to doing so. There are no more #include files, because the C# compiler automatically resolves project dependencies. In C# the operators -> and :: (unlike C++) don't exist, so if you want to access class members, use the dot operator ( . )
C# classes are reference types, so they are never allocated on the Stack; they are allocated on the Managed Heap. The Managed Heap is an area of memory that is managed by the Common Language Runtime, which has the ability to free unused memory blocks (objects) in a process known as Garbage Collection. When you have a variable that's not attached to an object:
Employee Michael;
You will not be able to access the object's members, and the variable Michael will reference to a block of memory which contains nothing, so we say of this variable that "it has a null reference" which means we can't use it. You must instantiate an object in order to use it:
Employee Michael = new Employee();
As we have said before, the new operator creates the object on the Managed Heap and returns the reference, which will be stored in the variable Michael.
You can control the visibility of class members for the other classes and other code using Access Modifier keywords: public, private, protected and internal. In C#, you must explicitly indicate the access modifiers for each member of you class, except from the private members, as we have observed. The next table discusses the available Access Modifiers:
Access Modifier
Description
public
States the the class member accessible for all the derived classes, classes in other assemblies and for any other code that want to you it.
private
It's the opposite of the public Access Modifier, states that the class member is not accessible for any code including derived classes so the only code that can access (or manipulate) this member is the declared class. Actually Object oriented Programming provide data protection using the private (and protected) Access Modifiers. For example, you can declare the salary field inside the Employee class as private and it will not be accessible and it will not be visible outside this class declaration so there's no client code that can modify its value unless you the programmer want that.
protected
This is an intermediate access level between the public and the private Modifiers. It states that the member is accessible for only derived classes which gives you the ability to declare fields that are not accessible outside the declared class and any class that derive it. For example, you can define a class like ManagerEmployee that derive and extend the Employee class.
internal
This is an interesting Access Modifier that states that the class member is accessible only for the current assembly (we will have our discussion about assemblies later). This means that the member is public for the assembly but it's not visible outside the assembly.
The "this" keyword gets you an access to an instance of the class, and you can use it with instance methods, instance constructors and instance properties. You can't use it with any static members; this makes sense because a static member works on the class itself, not on an instance of it. Use the "this" keyword followed by the (.) operator to get access to the class members on an instance object. Take a look at the following class:
using System; namespace Company { public class Employee { public string FirstName; public string LastName;
In the Employee class's default constructor I used the "this" keyword to initialize the public fields FirstName and LastName, so this keyword pretends that you already have an instance of the Employee class.
Class members
Inside a C# class you have defined: fields, properties, methods, constructors, destructor, indexers, constants, events, delegates and operators. We will discuss Fields, Constants and Static Types in this article; we will have separate articles for each of the other Class members.
A field is a class level variable, or you can call it a member variable. If you declare a field of a value type, it stores the data itself, but if you declare a field of a reference type, it stores a reference to where the actual data is allocated. You must be careful when you define member variables. Let's take an example:
using System; namespace MyCompany { public class Employee { public decimal Salary; }
public class EmployeeTest { static void Main(string[] args) { // this is client code that can modify the value of the Employee's salary Employee Michael = new Employee(); Michael.Salary = 10000; Console.WriteLine("Michael's salary = {0:C}",Michael.Salary); Michael.Salary = 0; Console.WriteLine("Michael's salary = {0:C}",Michael.Salary); Console.ReadLine(); } }
The class Employee has only one public field (Salary) which represents the employee's salary. The EmployeeTest class' Main method creates the instance Michael of type Employee, and the next statement sets the salary to $10,000. As you can see, the client code assigns the value to the public field Salary, and you don't have any kind of security over the process. Again, the Main method assigns 0 to the salary and writes it to the Console Window. You will get the following result:
Good Object oriented practice states that you must declare your fields as private, and provide provide public properties to access the fields (we will discuss properties later in the series, too, so don't worry). Let's look at the MSIL code for Employee class. Open the ILDASM tool and load the application, then navigate to the Employee class and double click on the Salary field:
The MSIL is just telling us that it's a public field of type System.Decimal, and it's called Salary. This means that when you instantiate the Employee class, the created object will have a block of memory for the Salary field; that is worth remembering.
With other programming languages we had a very common problem, which C# has vanquished. Suppose that you need a field to be initialized at runtime and never change after that. If you know the value at design time, you can use constants (as we will discuss shortly). You can declare your field with the keyword "readonly" to have this behavior, and once it has been initialized at runtime it will never change. You have only one place to initialize the "readonly" field, which is the class constructor. Turning back to our Employee class, we need a "readonly" field to hold the SSN that will dynamically return from a method; this method maybe will connect to a database server to get the SSN of the employee, so the SSN is not available at design time.
using System; namespace MyCompany { public class Employee { public decimal Salary; public readonly double SSN;
// class constructor public Employee() { SSN = this.GetSSN(); }
private double GetSSN() { //we will assume that we have connected to a database return 987654321; } }
public class EmployeeTest { static void Main(string[] args) { // this is client code that can modify the value of the Employee's salary Employee Michael = new Employee(); Console.WriteLine(Michael.SSN); Console.ReadLine(); } } }
Sometimes you know the value that you want to assign to your fields, and you need these values to remain unchanged. For example, in the employee class you may have a field for the maximum overtime hours per week, which will never change, and this information is available at design time. What you do? Use the "const" keyword to declare the field as constant, which means that its value will not change; it must be available at design time.
public class Employee { public decimal Salary; public const int MaxOverTimeHours = 10; }
Note that the value of the constant field must be literal, so you can't get the value as a return value from a method call. Load the ILDASM Tool, navigate to the Employee class, and double click the MaxOverTimeHours field.
This is the MSIL declaration for the constant field MaxOverTimeHours, and as you can see, it has been assigned the value (0xA) 10. Now let's try to use this field.
public class EmployeeTest { static void Main(string[] args) { Console.WriteLine(Employee.MaxOverTimeHours); Console.ReadLine(); } }
From the above constant field declaration, you can see that it's a static field, which means that you can't access the field with an object reference. You have to use the class name in order to access the static members. Think about it for a minute: why do we need an instance variable for a field whose value will never change? It will create a lot of unnecessary memory spaces, so C# defines it as static, because it will never change. Load the EmployeeTest class with the ILDASM tool and get to the main method:
The highlighted MSIL Instruction pushes the value 10 onto the stack, and the next Instruction calls the Console::WriteLine(Int32) method to print this value. As you can see, we don't have the MaxOverTimeHours constant field here; instead, the C# compiler replaces the field with the value.
A Static member is a member that has a class-level access, unlike instance members which must be called on an instance of the class. To call a Static member, simply use the class name followed by the (.) operator without creating an object from the class. Static members are useful for many scenarios.
Take the Console class as an example; to write a line to the console you use the static method WriteLine() of the Console class. In this scenario, it doesn't make sense to create an instance of the Console class and call WriteLine(), because all of the objects would write a line to the Console Window.
You can use static members to provide functionality that is not bound to an instance of the object; a class like Console can't be instantiated, and all its members are static. This is the perfect scenario, where we have some functionality and code that doesn't fit in the Object Oriented Programming Objects and Classes world, such as the Console class.
If you have a class that contains a static field and another instance field, note that each time you create an instance of the class, the CLR will allocate a memory location for the instance field, but, as for the static field, it will create only one memory location no matter how many objects you have. Think of the static members as class level members, and the instance members as per object data fields. Also remember that a static method can only manipulate static fields; we will discuss this issue in the methods article.
Turning back to our Employee class example, suppose that we need some way to track how many employee objects we have. Look at the following code:
using System; namespace MyCompany { public class Employee { public decimal Salary; public const int MaxOverTimeHours = 10; public static double EmployeeCounter;
public Employee() { EmployeeCounter++; } }
public class EmployeeTest { static void Main(string[] args) { Employee Michael = new Employee(); Employee Youssef = new Employee(); Employee David = new Employee(); Console.WriteLine(Employee.EmployeeCounter); Console.ReadLine(); } } }
The result of this code is 3. In the Employee class we added a public static field called EmployeeCounter, and in the default constructor of the Employee class (for now think of a constructor as a special type of methods that is called every time you create an instance of your class), we increase the EmployeeCounter by 1 for each new employee instance. In the EmployeeTest class we created 3 objects of type Employee, and printed the value of the EmployeeCounter field. Note that we used the class name in order to access the static field.
In the next article, we will discuss control C# program structure.