#347 – Another Example of Polymorphism

The power of polymorphism is that you can invoke methods in derived classes using a reference to the base class.

Assume that you have a Dog base class and a series of classes that derive from Dog.  You might define a generic Bark method in the base class and then a Bark method specific to each breed in each of the derived classes.

You can write a method that takes any Dog as a parameter and invokes that dog’s Bark method.

    static void BarkAndTell(Dog d)
        {
            d.Bark();
            Console.WriteLine("{0} just barked", d.Name);
        }

You can pass instances of the derived classes into this method.

            Terrier jack = new Terrier("Jack", 15);
            Shepherd kirby = new Shepherd("Kirby", 12);

            BarkAndTell(jack);
            BarkAndTell(kirby);

Polymorphism ensures that the  Bark method in the appropriate subclass is called, even though we’re referring to the instance using a variable whose type is the parent class (Dog).

#346 – Polymorphism

Recall that polymorphism is one of the three core principles of object-oriented programming.

Polymorphism is the idea that the same code can act differently, depending on the underlying type of the object being acted upon.  The type of the object is determined at run-time, rather than at compile-time.

In C#, you can use a variable declared as a base type to refer to instances of one or more derived types.  Polymorphism allows you to call a method that exists in the base type but whose implementation exists in the derived types.  The appropriate method in the derived type will be called, based on the type of the object.

            Dog d;

            d = new Terrier("Jack", 15);
            d.Bark();      // Terrier.Bark is called

            d = new Shepherd("Kirby", 12);
            d.Bark();      // Shepherd.Bark is called

#345 – Method in Derived Class Hides Base Class Method by Default

If you define a method in a derived class with the same name and signature as a method in the base class, the new method hides the base class method by default.  This is true even if you don’t use the new keyword to explicitly indicate that you intend to hide the method in the base class.

In other words, if we have a Dog.Bark method, the following two code snippets are functionally equivalent.

    public class Terrier : Dog
    {
        public new void Bark()
        {
            Console.WriteLine("Terrier {0} is barking", Name);
        }
    }

 

    public class Terrier : Dog
    {
        // No new keyword, but we're still hiding base class method
        public void Bark()
        {
            Console.WriteLine("Terrier {0} is barking", Name);
        }
    }

Without the new keyword, the compiler warns you that you’re hiding the base class method and recommends using the new keyword.

#344 – Hidden Base Class Member Is Invoked Based on Declared Type of Object

When you use the new modifier to hide a base class method, it will still be called by objects whose type is the base class.  Objects whose type is the derived class will call the new method in the derived class.

            Dog kirby = new Dog("Kirby", 15);

            // Calls Dog.Bark
            kirby.Bark();

            Terrier jack = new Terrier("Jack", 17);

            // Calls Terrier.Bark
            jack.Bark();

The Terrier.Bark method is invoked because the variable jack is declared to be of type Terrier.

We could also use a variable of type Dog (the base class) to refer to an instance of a Terrier (the derived class).  If we then call the Bark method using this base class variable, the Bark method in the base class is called, even though we’re invoking the method on an instance of the derived class.

            Dog kirby = new Dog("Kirby", 15);

            // Calls Dog.Bark
            kirby.Bark();

            Dog jack = new Terrier("Jack", 17);

            // Calls Dog.Bark
            jack.Bark();

#343 – Use the new Keyword to Replace a Method in a Base Class

A derived class inherits data and behavior from its parent class.

There are times when you might want to replace a method in a base class with a new method in the derived class, having the same name.  You can do this using the new keyword.

Assume a Dog class has a Bark method:

    public class Dog
    {
        public void Bark()
        {
            Console.WriteLine("Generic dog {0} says Woof", Name);
        }

You can provide a new version of this method in a class that derives from Dog, using the new keyword.  This new method hides the method in the base class.

    public class Terrier : Dog
    {
        public new void Bark()
        {
            Console.WriteLine("Terrier {0} is barking", Name);
        }

Dog objects will now invoke Dog.Bark and Terrier objects will invoke Terrier.Bark.

            Dog kirby = new Dog("Kirby", 15);
            kirby.Bark();

            Terrier jack = new Terrier("Jack", 17);
            jack.Bark();

#342 – Using a Static Variable to Count Instances of a Class

Recall that static variables in a class are not specific to a particular class, but that there is a single copy of each static variable regardless of the number of instances of the class that exist.

It’s fairly common to use a static variable to keep track of how many instances of a class have been created.

        // Total # of instances that have been created
        public static int NumDogs { get; protected set; }

        // Static constructor initializes NumDogs
        static Dog()
        {
            NumDogs = 0;
        }

        // Instance properties
        public string Name { get; set; }
        public int DogNumber { get; set; }   // unique dog-number, 1..n

        public Dog(string name)
        {
            Name = name;

            // Increment dog count and assign dog number
            NumDogs++;
            DogNumber = NumDogs;
        }

#341 – Defining and Using Local Variables

You can define variables within a method.  These are known as local variables.  The variables’ values can be read and written while the body of the method is executing.

The Dog.Bark method below defines two local variables–formalName and barkPhrase.

    public class Dog
    {
        public string Name { get; set; }
        public string BarkSound { get; set; }

        public void Bark()
        {
            string formalName = string.Format("Sir {0}", Name);
            string barkPhrase = string.Format("{0} {0}!", BarkSound);

            Console.WriteLine("{0} says {1}", formalName, barkPhrase);
        }
    }

Local variables can be initialized when they are declared, or they can be set to a value later.  Since C# requires definite assignment, they must be given a value before they are read.

 

#340 – Use the params Keyword to Pass a Variable Number of Arguments

When you define a method in a class, the parameters of the method normally dictate the exact number of arguments that you can pass to the method.  There are times, however, when you might want to pass a variable number of parameters to a method.

You could pass a variable number of parameters to a method by using an array.

        public void PerformCommands(string[] commandList)
        {
            foreach (string command in commandList)
                Console.WriteLine("Ok, I'm doing [{0}]", command);
        }

You’d call this method by creating a new instance of an array.

            kirby.PerformCommands(new string[] { "Sit", "Stay", "Come" });

To simplify things, you can use the params keyword in the method definition.  This allows passing the elements of the array as individual arguments.

        public void PerformCommands(params string[] commandList)

This makes calling the method a little cleaner.

            kirby.PerformCommands("Sit", "Stay", "Come", "Fetch");

#339 – Readonly Fields vs. Read-Only Properties

A read-only property in a class is similar to a readonly field.  Both expose a value that users of the class can read, but not write.

A readonly field is defined using the readonly modifier.  A read-only property is defined by including a get accessor for the property, but not a set accessor.

A readonly field can have only a single value, set either at the time that the field is declared, or in a constructor.  A read-only property returns a value that may be different each time the property is read.

Example of a readonly field:

        // Readonly field, initialized in constructor
        public readonly string OriginalName;

        public Dog(string name)
        {
            Name = name;

            // Set readonly field once, in the constructor
            OriginalName = name;
        }

Example of a read-only property:

        public string FormalName
        {
            get
            {
                return string.Format("Sir {0}", Name);
            }
        }

#338 – Static Readonly Fields vs. Constants

A static readonly field in a class is very similar to a constant.  Both expose a constant, static value that is associated with the class, independent of any instances of the class.

We could declare a static readonly field in a Dog class:

        public static readonly string TheDogMotto = "Man's Best Friend";

We could also declare this value as a constant:

        public const string TheDogMotto = "Man's Best Friend";

The value of a constant must be known at compile-time and specified as part of the declaration.

The value of a static readonly field is set at run-time, so it can be different from run to run.  It is specified in either the declaration or within a static constructor.

Use a readonly field for values that you won’t know until run-time or have to calculate.  Use a constant for values that are known and never change.