Sunday, February 8, 2004

Tutorial 2 - Access modifiers and properties primer

This builds off the last primer, Classes, objects and methods. This will quickly introduce you to access modifiers and properties.

Modifiers

There are several types of modifiers. In general, they are used to indicate how other classes may use the elements (variables, types, methods) of your class.

Access modifiers allow some parts of a class to be public (that is, usable by the rest of the world) and other parts to be private implementation details (hidden to the rest of the world). This helps provide encapsulation, or the ability to hide details of implementation away from other classes that should not know the inner workings.

The modifiers used in the Airplane example below include: public, private, const, readonly, and override

  • Members declared as public can be used outside the class.
  • Members declared private can only be used inside the class. Private is the default accessibility for members of a class.
  • Fields (or variables) declared as const are constants set at compile time.
  • Fields (or variables) declared as readonly can only be set during object initialization (construction) but never set or changed after that.
  • Override has to do with class inheritance, which is a later topic. It is used on the ToString() method since all objects have a method ToString() and we want to override, or change, the behavior of the default implementation for Airplane objects.

First, we add a public readonly field for MaxAltitude. This will be set when the airplane is constructed (presumably based upon the model of the aircraft).

       public readonly int MaxAltitude;

Next, we add a public const field for MaxSpeed. In this example we will assume all airplanes can travel at the same max speed (not very realistic, I'd like to see a Cessna trying to keep up with a F-15 Eagle).

       public const int MaxSpeed = 700;

All of our other fields will be set private, so that other classes do not try to do something stupid like make our airplane fly too fast or too high. This is a good time to introduce properties.

Properties

Properties allow the getting and setting of internal values (often private fields) through special get and set methods.

MSDN Link: Properties

For the airplane class we have a few private fields: direction, altitude and speed. By convention, private variables generally start with a lowercase letter. Sometimes people use _ or m_ as a prefix, but I prefer not to clutter code with prefixes.

The public properties Direction, Altitude, and Speed will allow others to get and set these private field. By convention, public members are capitalized. These properties will include two methods: get and set. The get method is used to get the value and set is used to set a new value. We implement error checking in the set methods to guarantee the integrity of our data (and our airplane, we don't want it going to fast!).

We also make readonly properties for manufacturer and model since these cannot be changed on an airplane once created. A readonly property does NOT use the readonly keyword. Instead, it implements just a get method with no corresponding set method.

Let's take a look at the new airplane class.

using System;

namespace TestAirplane
{
   public class Airplane
   {
       private string manufacturer;
       private string model;
       private float direction;
       private int altitude;
       private int speed;

       /// <summary>
       /// The Maximum Altitude that this plane can fly in ft.
       /// This is a readonly value that is set in the constructor,
       /// and cannot be changed by any other code.
       /// </summary>
       public readonly int MaxAltitude;

       /// <summary>
       /// The Maximum Speed that this plane can fly in mph.
       /// This is a constant that can not be changed by any other code.
       /// (All planes have a MaxSpeed of 700 mph, in this example.)
       /// </summary>
       public const int MaxSpeed = 700;

       /// <summary>
       /// Read-only property to get the manufacturer
       /// </summary>
       public string Manufacturer
       {
           get { return this.manufacturer; }
       }
      
       /// <summary>
       /// Read-only property to get the model
       /// </summary>
       public string Model
       {
           get { return this.model; }
       }

       /// <summary>
       /// Property to set the direction (heading) of the
       /// airplane.  Will be a bearing between 0 and 359 degrees
       /// where 0 is north, 90 east, 180 south, and 270 west.
       /// Range checking is performed to keep the direction
       /// between 0 inclusive and 360 exclusive.
       /// </summary>
       public float Direction
       {
           get { return this.direction; }
           set
           {
               float temp = value;
               if (Math.Abs(temp) >= 360.0F)
               {
                   temp = temp % 360.0F;
               }
               if (temp < direction =" temp;">
       /// A property to get or set the Altitude of an airplane.
       /// Range checking is used to prevent flying past the MaxAltitude.
       /// </summary>
       public int Altitude
       {
           get { return this.altitude; }
           set {
               if (value < altitude =" 0;"> MaxAltitude)
               {
                   Console.WriteLine("Can't fly that high: " + value);
                   this.altitude = MaxAltitude;
               }
               else
               {
                   this.altitude = value;
               }
           }
       }

       /// <summary>
       /// A property to get or set the speed.
       /// Range checking is used to prevent flying past the maximum speed.
       /// </summary>
       public int Speed
       {
           get { return this.speed; }
           set
           {
               if (value < speed =" 0;"> MaxSpeed)
               {
                   Console.WriteLine("Can't fly that fast: " + value);
                   this.speed = MaxSpeed;
               }
               else
               {
                   this.speed = value;
               }
           }
       }

       /// <summary>
       /// A constructor used
       /// to create a new Airplane instance.
       /// </summary>
       /// <param name="manufacturer">The manufacturer of the airplane
       /// <param name="model">The model of the airplane
       /// <param name="maxAltitude">The maximum altitude that
       /// this plane can cruise.
       public Airplane(string manufacturer, string model, int maxAltitude)
       {
           this.manufacturer = manufacturer;
           this.model = model;
           MaxAltitude = maxAltitude; // can only be set here.
           this.altitude = 0;
           this.direction = 0;
           this.speed = 0;
       }

       // Make the airplane takeoff
       public void TakeOff ()
       {
           this.altitude = 30000;
           this.speed = 500;
       }
      
       // Make the airplane land
       public void Land ()
       {
           this.altitude = 0;
           this.speed = 0;
       }

       // Set a new course for the airplane
       public void SetCourse (int newDirection)
       {
           this.direction = newDirection;
       }

       // override is used because all objects
       // have a default ToString() method, we want
       // to override that default method with this
       // new method.
       public override string ToString()
       {
           string message;
           if (altitude == 0)
           {
               message = this.manufacturer + " " + this.model +
               " is currently on the ground.";
           }
           else
           {
               message = this.manufacturer + " " + this.model +
                   " flying " + this.speed + " mph" +
                   " with bearing " + this.direction +
                   " at an altitude of " + this.altitude + " ft.";
           }
           return message;
       }
  
       public static void Main ()
       {
           // Create an airplane (Boeing 747) with a max altitude of 40000 ft.
           Airplane airplane1 = new Airplane ("Boeing", "747", 40000);
           // Make it take off
           airplane1.TakeOff();
           airplane1.SetCourse (90);
           // Display information about the airplane.
           // Notice, that ToString() is called automatically by WriteLine.
           Console.WriteLine(airplane1);
          
           // Now increase speed a lot!
           airplane1.Speed *= 100;
           // Try to fly really high.
           airplane1.Altitude = 100000;
           Console.WriteLine(airplane1);

           // Now land.
           airplane1.Land();
           Console.WriteLine(airplane1);
           Console.ReadLine();
       }
   }
}

This class is still fairly simple. Cut & paste it into an editor, save, compile and run it to see the results.

One other thing to note, XML-style comments were used above. These allow for the creation of very professional documentation directly from your source code.

MSDN Link: XML Commenting

Tool link: Ndoc

No comments: