This C# primer is part 2 of a series intended for programmers who would like to ramp up quickly. Get part 1 here. C# is the latest in an evolutionary line of C-based programming languages which includes C, C++, and Java. It was used by Microsoft to develop much of the code for the . NET Framework and is considered by many to be the language of choice for . NET development. This series of articles will provide an introduction to the C# language.
While early versions of C++ were implemented by bolting a preprocessor onto the C compiler, C# is designed from the ground up to be a modern, object-oriented language. The fundamental building block of a C# application is the class.
Listing A.2 presents a short program in which we use a class to define a new type called Person .
public Person(string firstName, string lastName, int age) {
Console.WriteLine(firstName + " " + lastName);
get { return age; } // get age
set { age = value; } // set age field
get { return lastName; } // get lastName
// create an instance of the Person class...
// this causes the Person constructor to execute...
Person p = new Person("Joe", "Bloggs", 33);
// call the DisplayName method...
p.DisplayName(); // displays "Joe Bloggs"
// display the age property...
Console.WriteLine("Age is " + p.Age); // displays "Age is 33"
// display the LastName property...
Console.WriteLine("Last name is " + p.LastName);
// display the updated age property...
Console.WriteLine("Age is " + p.Age); // displays "Age is 34"
We define a class using the class keyword followed by the name of the class and then the class body contained in curly braces. In this example, the Person class body contains fields, methods, and properties. These are collectively known as class members. Fields, also called data members, are regular variables. Methods, also known as function members, contain executable code.
The Test class in listing A.2 is used to execute the program and create an instance of the Person class:
Person p = new Person("Joe", "Bloggs", 33);
This creates a reference p to an instance of the Person class. Creating a class instance causes a special method, known as a constructor, to be executed. A constructor method always has the same name as the class itself and no return type. It is executed automatically when an instance of the class is created at run time. In this case, the constructor takes three arguments representing the first name, last name, and age of the person. These values are used by the constructor to initialize the fields in the class instance, as in:
The this keyword is used within a method to reference the current class instance.
The DisplayName method is used here to display the firstName and lastName fields. The method is called using the ref.MethodName(...) syntax:
In C#, the dot operator is typically used for member access. C# also supports C-style pointers and pointer member access ( p->m ) when operating in an unsafe context, denoted by the use of the unsafe modifier in a type or member declaration.
Note that all methods, except the constructor, must declare a return type. If a method does not return a value, then it should declare a void return type, as DisplayName does in listing A.2.
It is generally considered poor programming practice to allow calling code to reach into a class instance and change field values. Instead, C# provides properties for this purpose:
get { return age; } // get age
set { age = value; } // set age field
A property may have a get and/or set accessor associated with it. In this example, the get accessor returns the value of the age field. The set accessor is used to set the value of the age field. Within a set accessor block, C# automatically provides a variable called value which holds the new value to which the property can be set, as follows:
Note that the methods and properties of the Person class are marked with the access modifier public . (We look at the full list of access modifiers later in this article.) This makes them publicly accessible to calling code through a reference to the class instance, as in p.Age . Members which omit an access modifier, such as the fields in the Person class, are private by default. This means that they are inaccessible outside the class. Therefore the following attempt to access the firstName field will generate a compiler error:
Console.WriteLine("First name is " + p.firstName); // error!
The recommended naming convention is that private member names should begin with a lowercase letter while other member names should begin with an uppercase letter. However, this is not a rule.
A class can include static members which can be accessed without first creating an instance of the class. For example, the following snippet defines a static MinimumAge field in the Person class:
public static int MinimumAge = 18;
We can access the static MinimumAge field directly using the class name, as follows:
Since C# does not provide global variables, static fields are often used to store global values.
Finally, classes can be nested:
The class is at the heart of object-oriented programming in C#. We'll return to this topic when we consider inheritance.
C# provides the ability to create a lightweight class using a struct . Structs are value types and are created on the stack at run time. (Refer to chapter 2 of Microsoft .NET for Programmers for a complete discussion of value and reference types.) This removes the overhead of using references and obviates the need for garbage collection. The following example uses a struct to create a type that stores the x and y coordinates of a point:
Although a struct can contain methods, typically structs are used for types that contain just a few data members. Like classes, structs can also be nested. However, unlike a class, a struct may not inherit from another class or struct, nor may it serve as a base class for inheritance purposes.
C# allows us to design a class by using inheritance to embrace and extend an existing class. Unlike C++, which supports multiple inheritance, C# supports only single inheritance. However, like Java, C# also supports implementation inheritance using interfaces which provide some of the advantages of multiple inheritance. We'll explore interfaces later in this article.
Many application domains contain hierarchies that are naturally modeled by inheritance. Object-oriented GUI libraries often use this technique. For example, depending on the implementation, a check box may be a special type of button, and a button is a control, and a control is a type of component, and a component is an object. In such cases we might implement this as an inheritance hierarchy. The check box would extend the button class by adding a checked property, and so forth. A class that inherits from another is sometimes referred to as a derived class.
Let's return to our Person class. Listing A.3 provides a new implementation of the Person class, together with a class called Man which derives from Person .
protected string firstName, lastName;
public Person(string firstName, string lastName) {
Console.WriteLine("Hello " + firstName + " " + lastName + "!");
// Man derives from Person class...
// create a Man by calling base Person constructor...
public Man(string fName, string lName) : base(fName, lName) {}
// replace base Greet method with a new implementation...
Console.WriteLine("Hello Mr. " + lastName + "!");
Person p = new Person("Joe", "Bloggs");
p.Greet(); // displays "Hello Joe Bloggs!"
Man m = new Man("Joe", "Bloggs");
m.Greet(); // displays "Hello Mr. Bloggs!"
Inheritance is used to model an is-a relationship. (A man is a person). In this example, we've changed the accessibility of the firstName and lastName fields of the Person class to protected , thus making them accessible to any derived class. We specify that Man derives from Person , as follows:
// Man derives from Person class...
The only difference between the Man and Person classes is the greeting displayed. Therefore, we leverage the base Person class constructor to build an instance of Man , as follows:
// create a Man by calling base Person constructor...
public Man(string fName, string lName) : base(fName, lName) {}
The base keyword is used to refer to the parent object. In this example, the body of the Man constructor is empty. Instead the Person constructor is called to construct the object.
In the derived Man class, we reimplement the Greet method using the new keyword to make clear to the compiler that we are not inadvertently hiding the parent's Greet method.
One of the advantages of inheritance is the ability to use a base class reference to refer to an instance of a derived class. This allows us to write code without caring whether the reference is to a parent or derived class, as follows:
Person p = new Man("Joe", "Bloggs");
p.Greet(); // problem? calls base class Greet method
Here, we create a reference p to a Person object, but store in it a reference to a Man object. This is fine, but calling p.Greet() calls the base class Greet method, which is probably not what we intended. The solution lies in virtual methods. See listing A.4.
protected string firstName, lastName;
public Person(string firstName, string lastName) {
// Greet method is now marked virtual...
Console.WriteLine("Hello " + firstName + " " + lastName + "!");
// Man derives from Person class...
// create a Man by calling base Person constructor...
public Man(string fName, string lName) : base(fName, lName) {}
// override base Greet method with a new implementation...
public override void Greet() {
Console.WriteLine("Hello Mr. " + lastName + "!");
Person p1 = new Person("Joe", "Bloggs");
p1.Greet(); // displays "Hello Joe Bloggs!"
Person p2 = new Man("John", "Doe");
p2.Greet(); // displays "Hello Mr. Doe!"
Placing the virtual modifier in front of the base class's method definition causes the compiler to generate code to look up a data structure, known as a virtual dispatch table, at run time to find the correct method. A corresponding override modifier is required in front of the derived class's method in order for virtual dispatching to locate the correct method. So virtual dispatching allows an object to assume different forms, Man or Person in this example, as necessary. This is sometimes referred to as polymorphism.
Let's assume that we are interested in modeling men and women, but not persons per se. In other words, while both are persons, we don't want to allow the creation of Person objects directly. Instead, we only allow the creation of Man and Woman objects directly. However, we want both to inherit from, and share the implementation of, the Person class. We can do this using an abstract Person class, as seen in listing A.5.
protected string firstName, lastName;
public Person(string firstName, string lastName) {
// force derived classes to implement the Greet method by...
public Man(string fName, string lName) : base(fName, lName) {}
public override void Greet() {
Console.WriteLine("Hello Mr. " + lastName + "!");
public Woman(string fName, string lName) : base(fName, lName) {}
public override void Greet() {
Console.WriteLine("Hello Ms. " + lastName + "!");
Man m = new Man("Joe", "Bloggs");
m.Greet(); // displays "Hello Mr. Bloggs!"
Woman w = new Woman("Jane", "Doe");
w.Greet(); // displays "Hello Ms. Doe!"
We use the abstract modifier in front of the Person class definition to prevent the class being instantiated. Attempting to instantiate the Person class causes a compiler error. We also declare the Greet method to be abstract, thus requiring all derived classes to override this method. In other words, the Person class specifies a template, or contract, for classes which derive from it.
You can disable further inheritance by marking a class sealed :
Any attempt to use a sealed class as a base class for inheritance purposes will result in a compiler error. Use the sealed modifier to prevent unintended derivation.
In this series, we looked at classes and inheritance. In the next and final part of the series, we'll look into more about methods. If you would like to see the first part of the series, click here. If you would like to know more about C# or the Microsoft .NET platform, check out the book, Microsoft .NET for Programmers, which was written by the author of this article series. You can also check out Manning's Dot Net Corner community pages. Check back soon for the last article in this series.