#616 – Base Class Needs to Know If Polymorphism Is Desired

Let’s say that you design a Dog class that contains a Bark method and that you don’t do anything special to design for inheritance.

    public class Dog
    {
        public void Bark()
        {
            Console.WriteLine("Woof");
        }
    }

Now let’s say that you define several classes that inherit from Dog and provide their own implementation for the Bark method.  Because Dog.Bark was not marked as virtual, they must use the new keyword.

    public class Terrier : Dog
    {
        public new void Bark()
        {
            Console.WriteLine("Terrier says Grrrr");
        }
    }

But now you do not get polymorphic behavior when treating instances of Terrier as instances of Dog.

        static void Main()
        {
            Terrier t = new Terrier();
            t.Bark();  // Terrier.Bark
            SomeoneBark(t);
        }

        static void SomeoneBark(Dog d)
        {
            d.Bark();  // Dog.Bark always invoked--no polymorphism
        }

To achieve polymorphism, you must design for it in the base class by marking a method as virtual.

Advertisements

#615 – You Can’t Remove a Base Class Member

A subclass class inherits public members from its base class.  Below, the Terrier class inherits the Name property and the Bark method from the Dog class.

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

        public void Bark()
        {
            Console.WriteLine("Woof");
        }
    }

    public class Terrier : Dog
    {
        public string Temperament { get; set; }
    }
            Terrier jack = new Terrier();
            jack.Bark();   // Woof

The Terrier class can provide a new implementation of the Bark method:

    public class Terrier : Dog
    {
        public string Temperament { get; set; }

        public new void Bark()
        {
            Console.WriteLine("Grrr, growf!");
        }
    }

But you can’t completely remove the Bark method from the Terrier class.  If you try making the Bark method in Terrier private, when you invoke the Bark method on a Terrier object, the method in the parent Dog class will be called instead.

#614 – Subclass Accessibility

A class can be defined with one of two different levels of accessibility:

  • public – all code can use the class
  • internal – only code in the same .exe or .dll can use the class

When you define a subclass, the accessibility of the subclass must be the same as, or less accessible than, the parent class.

This means:

  • If the parent class is public
    • Subclass can be public or internal
  • If the parent class is internal
    • Subclass must be internal

#613 – Interfaces Cannot Contain Static Members

An interface is a list of methods, properties, events and indexers that a class may implement.  All methods, properties and events defined in the interface are implicitly instance members, rather than static members.

    public interface IDogStuff
    {
        bool CanBark { get; set; }
        void Bark();

        // Compile-time Error: The modifier 'static' is not valid for this item
        static string GenerateMotto();

    }

#612 – Members of an Interface Are Implicitly Public

The idea of an interface is to define a contract that a class can choose to implement.  Since an interface is a public definition of a contract, it doesn’t make sense for members of an interface to be private.  This means that all members in an interface are implicitly public.

    public interface IDogStuff
    {
        // Implicitly public
        bool CanBark { get; set; }
        void Bark();

        // Compile-time Error: The modifier 'public' is not valid for this item
        public void Fetch();

        // Compile-time Error: The modifier 'private' is not valid for this item
        private void PeeOnTree();
    }

#611 – Accessibility of Members in a struct

Methods, field and properties within a struct can have one of three access modifiers, dictating the visibility of these members.

  • public – all code has access
  • private – only code within the struct has access
  • internal – code within the defining assembly has access
    public struct DogBark
    {
        public string BarkSound;
        public int BarkLength;

        // Constructor is public
        public DogBark(string barkSound, int barkLength)
        {
            BarkSound = barkSound;
            BarkLength = barkLength;
            hash = barkSound.GetHashCode();
        }

        // internal - accessible from code in the same assembly
        internal int GetHash()
        {
            return hash;
        }

        // private - accessible from code in this struct
        private int hash;
    }

#610 – Lazy Evaluation in Property Get Accessors

One of the benefits in using a property in a class, rather than a public field, is that you can delay calculation of the property’s value until client code actually tries to read the value.

In the code below, we define a FullDogDescription property that is read-only.  The private backing variable is initialized to an empty string and we only calculate its value in the get accessor when someone tries to read the property’s value.

<pre>        private string fullDogDescription = "";
        public string FullDogDescription
        {
            get
            {
                // Generate full description the first time that
                // someone reads this property.
                if (fullDogDescription == "")
                    fullDogDescription = GenerateDogDescription();

                return fullDogDescription;
            }
        }

The benefit of doing this is that if the call to GenerateDogDescription takes some time, we don’t spend the time calculating a value until some piece of code actually needs a value.