University of the West of England, Bristol

Bristol Institute of Technology


C# Revision Worksheet 6 - Objects and Data


Learning Aims

This worksheet we'll look at how we can store data inside objects and at ways we can use and manipulate that data.

When you've completed this worksheet, you should be able to:


Theory Section (Part 1)

Making Objects Useful

By now, you should be fairly happy with the ideas behind creating a class (worksheet 2), making an object from that class (worksheet 2), and then calling methods belonging to that object (worksheets 4 and 5).

However, if these were the only facilities that objects offered, then there would be little difference between Object Oriented programming and the older, non-OO style of programming. So little difference that we just wouldn't bother with it!

Fortunately, objects offer far more facilities than you've looked at. One hugely important feature is that an object can store some data inside it. (This might seem completely underwhelming but in practice it's extremely important).

Let's Go Motoring

Even if you're not a car driver, you'll probably know that most cars have a gear selector lever allowing the driver to operate the car engine at the speed which offers the best power output. To pull away from stationary, the driver selects 1st gear. As the car's speed increases, the driver selects 2nd, 3rd, and finally 4th gear (many cars also have a 5th gear). The driver may also select reverse gear, to make the car travel backwards for parking, etc. There's also a neutral setting, which disconnects the engine from the wheels.

Let's think about how we might create a Car class, modelling the gear change behaviour of a typical car...

Obviously, we need to start with a class, thus:

using System;
using System.Collections.Generic;
using System.Text;
namespace somename
{
    class Car
    {
    }
}

This now begs the question: how do we represent the currently selected gear in C#?

If we use 0 for neutral, -1 for reverse, and 1,2,3,4 for the gear selections then we could use an int variable. For example: int gear;

But where to put the declaration? So far, we have only put variables inside methods, but our Car class doesn't have any methods (yet). Obviously, you have no choice but to put it directly inside the class. The modified Car class now looks like this:

using System;
using System.Collections.Generic;
using System.Text;
namespace somename
{
    class Car
    {
	    int _gear;
    }
}

Such a variable, placed inside the class but not inside any particular method has a special name. It's called a field.

Note the common naming convention that a field name in a class should begin with underscore _
C# does not actually require this, but it can be a very useful thing to do so we'll stick with it.

Let's add a few more fields to the class:

using System;
using System.Collections.Generic;
using System.Text;
namespace somename
{
    class Car
    {
        string _make;
        string _model;
        int _gear;
    }
}

The extra two fields record the make and model of the car. Possible values for these attributes might be "Skoda" "Fabia", or "Ford" "Ka", "Volkswagen" "Polo" or "Posche" "911".

If you look in some text books, they might mark fields public, private or even protected. For beginners, it doesn't really matter and we suggest that you don't bother with any of these. Later on, this will become an important issue.

Practical Section (Part 1)

  1. Start up Game Studio Express and create a new "Console Application" project called CarTest. As always, immediately Save All and then rename Program.cs to CarTest.cs

  2. Within Game Studio Express, create a new C# class called Car.cs

  3. Type in the complete Car class that appears above, using CarTest for the namespace name.

  4. Build this project and get rid of any compilation errors. You may get some warning messages (indicated by a yellow triangle) which you can ignore.
    Don't try to run it just yet.

Theory Section (Part 2)

Do It Yourself Car Factory

When a car is being driven in the city, the driver must necessarily change gear at frequent intervals. However, once a car has been manufactured, it never changes its make and model. You don't get into a Skoda Fabia and halfway to college find that it's changed into a Ford Ka.

The make and model are set when the car is manufactured and it would be convenient if C# allowed us to model this. That way, as you create a new car, you could simultaneously state its make and model.

Let's have a look at how we can do this in C#:

    Car bobsCar = new Car("Skoda", "Fabia");
    Car mikesCar = new Car("Ford", "Ka");
    Car jillsCar = new Car("Volkswagen", "Polo");

If you think that the underlined words above look just like a method call, with the make and model as actual parameters, then you'd be right.

There is a special method you can call as you create a new object. This special method is called the constructor.

Constructor Method

Every class can have a constructor. The constructor is called whenever an object (of that class) is created and its job is to set the attributes to some initial values. Usually, a constructor uses parameters to obtain those values.

Unlike the other methods you've looked at so far, the name of the constructor must be the same as the name of the class. Hence the constructor method in the Car class must be named Car(). You cannot give it any other name!

The constructor can only be called when an object is created and at no other time. In other words, it can only follow the word new as in the examples given in the previous section.

The constructor should never be marked void (or any other type).

A well designed constructor should ensure that all the attributes of a class are set to known values. Here is the constructor for the Car class:

  public Car(string requiredMake, string requiredModel) {
    // Save the car's make and model
    _make = requiredMake;
    _model = requiredModel;
    // Set gear to neutral
    _gear = 0;
  } // Car

As you can see, the method accepts the required make and model as parameters and simply copies them to the appropriate attributes. It also sets the gear field to 0 (neutral).

A note on the parameter names: you can see that we chose the names requiredMake and requiredModel for the parameters to the constructor. These are acceptable enough choices, but a professional programmer would probably prefer to use the simpler and shorter names: make and model. These names are very similar to the actual field names we chose (_make and _model) except that the field names always begin with an underscore.

Let's see how the various names are related...   Field: _make       Property: Field        Parameter: make

The names look very similar to the eye, but they sufficiently different so that C# doesn't get confused. With a bit of practice we can look at any one of them and immediately identify it as a field, property or parameter! This makes the code easier to write and easier to understand later on.

Practical Section (Part 2)

  1. Modify your Car class to include the constructor method shown above. It should look like this when you've finished:
  2. using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace CarTest
    {
        class Car
        {
            string _make;
            string _model;
            int _gear;
    
            public Car(string make, string model)
            {
                // Save the car's make and model
                _make = make;
                _model = model
    
                // Set gear to neutral
                _gear = 0;
            }
        }
    }
  3. Edit the file CarTest.cs, so that its Main() method looks like this:
  4. static void Main(string[] args) 
    {
        Car bobsCar = new Car("Skoda", "Fabia");
        Car mikesCar = new Car("Ford", "Ka");
        Car jillsCar = new Car("Volkswagen", "Polo");
    }
      
  5. Build and run this program, but don't be surprised when it doesn't produce any output!

Theory Section (Part 3)

PrintState Method

When you ran your CarTest program, it didn't produce any output and so you can't really be sure that the Car class really worked as advertised.

What's needed is another method which prints out the current state of the car - that is, the value of every attribute. Here's a suitable method for the Car class:

public void PrintState()
{
    Console.Write(_make);
    Console.Write(" ");
    Console.Write(_model);
    Console.Write(" in gear ");
    Console.WriteLine(_gear);
}

When your program calls this method, it prints out the values of the three attributes.

Practical Section (Part 3)

  1. Add the PrintState() method to your Car class and compile it.

  2. Modify the Main() method of CarTest so that it now includes a call to PrintState(), like this:
  3. static void Main(string[] args) 
    {
        Car bobsCar = new Car("Skoda", "Fabia");
        Car mikesCar = new Car("Ford", "Ka");
        Car jillsCar = new Car("Volkswagen", "Polo");
        bobsCar.PrintState();
        mikesCar.PrintState();
        jillsCar.PrintState();
    }
  4. Compile this program and get it running. It should produce the following output:
  5. Skoda Fabia in gear 0
    Ford Ka in gear 0
    Volkswagen Polo in gear 0
      

Theory Section (Part 4)

Changing Gear

When driving, the driver doesn't often think in terms of actual gear numbers, but rather whether it's necessary to go up a gear, or down a gear. We can simulate this by adding two more methods to the class:

Here's a very simple form of one of these methods. The other one is very similar.

public void GearUp()
{
    _gear++;
}

Practical Section (Part 4)

  1. Modify your Car class to include GearUp() and your version of GearDown()
  2. Modify the Main() method of CarTest, so it now looks like this:
    static void Main(string [] args) 
    {
        Car testCar = new Car("Renault", "Clio");
        testCar.gearUp ();
        testCar.gearUp ();
        testCar.gearUp ();
        testCar.gearDown ();
        testCar.printState ();
    }
  3. Build and run this program. What output would you expect it to produce?

  4. Modify this program so that it calls GearUp () at least six times in succession. (Use PrintState() after each gear change).
    What happens to the gear number, and why is this unrealistic?

  5. Does a similar problem occur when GearDown() is called a several times in succession?
    (Hint: The problem with GearUp() and GearDown() is that they allow the gear field to be set to inappropriate values, such as 6,-2 or -3.

  6. Use an if statement in GearUp() to prevent the car from going into a gear higher than 4. Try it out before looking at the answers below.

  7. Use an if statement in GearDown() to prevent the car from going into a gear lower than 1. Try it out before looking at the answers below.


Theory Section (Part 5)

Getting a Field Value

Within the class, we can use any field as if it were a normal variable; however, what happens if we try to access a field from outside the class?
Simple. We can't! Access is forbidden and if we try we get an error message when we try to build the program.

However, we sometimes need to get access to a field from outside, and C# allows this in an extremely elegant manner: the class property

Defining a Property

Let's define a property to enable access to the car's make. Remember that _make is defined as a string field in the Car class:

public string Make 
{
    get { return _make; }
}
Notes:

Using a Property

Using a property is very simple: just put a dot followed by the property name. For example, we can obtain the make of bobsCar into a string variable like this:

    string bobsMake = bobsCar.Make;
and we can print it out directly like this:
    Console.WriteLine(bobsCar.Make);

Note that in each case, we always use the property name (Make with a capital M) and not the field name (_make with a small m).

Practical Section (Part 5)

  1. Modify the Car class to include the Make property given above.
  2. Modify the Main() method of CarTest, so it now looks like this:
    static void Main(string [] args) 
    {
        Car bobsCar = new Car("Skoda", "Fabia");
        Car mikesCar = new Car("Ford", "Ka");
        Car jillsCar = new Car("Volkswagen", "Polo");
    	
        Console.Write("Bob's car is a ");
        Console.WriteLine(bobsCar.Make);
    	
        Console.Write("Mike's car is a ");
        Console.WriteLine(mikesCar.Make);
    
        Console.Write("Jill's car is a ");
        Console.WriteLine(jillsCar.Make);
    }
  3. Build and run this program. What output would you expect it to produce?
  4. Add a similar property called Model to the Car class.
  5. Modify the Main() method to make use of the Model you just added to Car

Theory Section (Part 6)

Setting a Field Value

So far, we've only put a get method into our Properties. This means that an outside class can obtain a field's value, but can't actually change it. If we want to allow an outside class to change a field, then we must put a set method in the corresponding property. Let's try this with a property for the gear field:

public int Gear {
    get { return _gear;}
    set { _gear = value; }
}

The set method looks very similar to the get method, except that it assigns a value to the _gear field. The value assigned is represented by the word value, which is a C# reserved word.

Note that the property name is preceded by the type int which is the type of the _gear field.

Once the get method is set up, we can directly assign any value to the property.

    bobscar.Gear = 4;

Of course, we can stil use the GearUp() and GearDown() methods which we have previously defined.

Practical Section (Part 6)

  1. Add the Gear property to the Car class.
  2. Modify the Main() method of CarTest.cs, so it now looks like this:
  3. static void main (String [] args) {
        Car bobsCar = new Car("Skoda", "Fabia");
        Car mikesCar = new Car("Ford", "Ka");
        Car jillsCar = new Car("Volkswagen", "Polo");
    	
        bobsCar.Gear = 1;
        bobsCar.PrintState();
    	
        mikesCar.Gear = 2;
        mikesCar.GearDown();
        mikesCar.PrintState();
        
        jillsCar.Gear = 3;
        jillsCar.GearDown();
        JillsCar.GearDown();
        Console.WriteLine("Jill's car is in gear {0}", jillsCar.Gear);
    }
        
  4. Build this program and get it running. Confirm that the output you get is correct
  5. Put the following line in the Main() method:
  6.     jillsCar.Gear = 6;
      
  7. Build the program and get it working.
    Why is it unrealistic to set the _gear to 6?

Theory Section (Part 7)

Putting Checks in the set Method

We saw in the previous section, that it is possible to assign unrealistic values to the Gear property (and hence the _gearfield). We put checks (if statements) inside the GearUp() and GearDown() methods, so perhaps we need to put similar checks inside the set method, like this:

public int Gear {
    get { return _gear;}
    set 
    {
      _gear = value; 
      if (_gear < 1) _gear = 1;
      if (_gear > 4) _gear = 4;
    }
}

The addition of the two if statements now constrains the _gear field to be in the range 1 to 4. These statements are executed invisibly each time a value is asssigned to the Gear property. If the programmer attempts to assign a value below 1 then the first if statement forces the _gear field to 1. Similarly, if the programmer attempts to assign a value above 4 then the second if statement forces the _gear field to 4.

What about Neutral and Reverse?

Because we've now constrained all our methods we can no longer put a car into neutral (_gear = 0) or reverse (_gear = -1).

The obvious solution is to add two more methods: PutInNeutral() and PutInReverse(). These methods are very simple and you should try to write them yourself. Hint: these methods should write to the _gear field and not to the Gear property. Why?

Practical Section (Part 7)

  1. Modify the Gear property of the Car class to include the new version of set.
  2. Add your own versions of PutInNeutral() and PutInReverse() into the Car class.
  3. Modify the Main() method of CarTest to include tests for the new version of set and the two new methods.
  4. Build this program and get it running. Confirm that the output you get is correct.

What You Did - and What You've Learned

In this worksheet, you performed the following steps:

You have learned the following information about C#:


Methods to Change Gear

public void GearUp() 
{
  if (_gear < 4) {
    _gear++;
  }
}

public void GearDown() 
{
  if (_gear > 1) {
    _gear--;
  }
}


Revision Worksheets Index Page