Classes in C#
- Declaring and Instantiating a Class
- Instance Fields
- Instance Methods
- Using the this Keyword
- Access Modifiers
- Properties
- Constructors
- Static Members
- Extension Methods
- Encapsulating the Data
- Nested Classes
- Partial Classes
- Summary
You briefly saw in Chapter 1 how to declare a new class called HelloWorld. In Chapter 2, you learned about the built-in primitive types included with C#. Since you have now also learned about control flow and how to declare methods, it is time to discuss defining your own types. This is the core construct of any C# program; this support for classes and the objects created from them is what makes C# an object-oriented language.
This chapter introduces the basics of object-oriented programming using C#. A key focus is on how to define classes, which are the templates for objects themselves.
All of the constructs of structured programming from the previous chapters still apply within object-oriented programming. However, by wrapping those constructs within classes, you can create larger, more organized programs that are more maintainable. The transition from structured, control-flow-based programs to object-oriented programs revolutionized programming because it provided an extra level of organization. The result was that smaller programs were simplified somewhat. Even more importantly, it was easier to create much larger programs because the code within those programs was better organized.
One of the key advantages of object-oriented programming is that instead of creating new programs entirely from scratch, you can assemble a collection of existing objects from prior work, extending the classes with new features, adding more classes, and thereby providing new functionality.
Readers unfamiliar with object-oriented programming should read the Beginner Topic blocks for an introduction. The general text outside the Beginner Topics focuses on using C# for object-oriented programming with the assumption that readers are already familiar with object-oriented concepts.
This chapter delves into how C# supports encapsulation through its support of constructs such as classes, properties, and access modifiers; we covered methods in the preceding chapter. The next chapter builds on this foundation with the introduction of inheritance and the polymorphism that object-oriented programming enables.
Declaring and Instantiating a Class
Defining a class involves first specifying the keyword class, followed by an identifier, as shown in Listing 5.1.
LISTING 5.1: Defining a Class
class Employee { }
All code that belongs to the class will appear between the curly braces following the class declaration. Although not a requirement, generally you place each class into its own file. This makes it easier to find the code that defines a particular class, because the convention is to name the file using the class name.
Once you have defined a new class, you can use that class as though it were built into the framework. In other words, you can declare a variable of that type or define a method that takes a parameter of the new class type. Listing 5.2 demonstrates such declarations.
LISTING 5.2: Declaring Variables of the Class Type
class Program
{
static void Main()
{
Employee
employee1, employee2;
// ...
}
static void IncreaseSalary(Employee
employee)
{
// ...
}
}
Now that you have defined a new class type, it is time to instantiate an object of that type. Mimicking its predecessors, C# uses the new keyword to instantiate an object (see Listing 5.3).
LISTING 5.3: Instantiating a Class
class Program
{
static void Main()
{
Employee employee1 = new Employee();
Employee employee2;
employee2 = new Employee();
IncreaseSalary(employee1);
}
}
Not surprisingly, the assignment can occur in the same statement as the declaration, or in a separate statement.
Unlike the primitive types you have worked with so far, there is no literal way to specify an Employee. Instead, the new operator provides an instruction to the runtime to allocate memory for an Employee object, instantiate the object, and return a reference to the instance.
Although an explicit operator for allocating memory exists, there is no such operator for de-allocating the memory. Instead, the runtime automatically reclaims the memory sometime after the object becomes inaccessible. The garbage collector is responsible for the automatic de-allocation. It determines which objects are no longer referenced by other active objects and then de-allocates the memory for those objects. The result is that there is no compile-time–determined program location where the memory will be collected and restored to the system.
In this trivial example, no explicit data or methods are associated with an Employee, which renders the object essentially useless. The next section focuses on adding data to an object.