#1,042 – Deriving from a Self-Referencing Constructed Type, Part I

When defining a type, the type can derive from a constructed generic type.

public class DogList : List<string>

You can use the name of the type being defined as the type argument to the type (or interface) that you’re deriving from.

Below, the Dog type is an argument to the IComparable generic interface.  We’re saying that we want Dog to implement IComparable<T> and it makes sense that the argument should be Dog.

    public class Dog : IComparable<Dog>
    {
        public string Name { get; set; }
        public int WoofPower { get; set; }

        public Dog(string name, int woofPower)
        {
            Name = name;
            WoofPower = woofPower;
        }

        public int CompareTo(Dog other)
        {
            // Returns
            //   < 0 if this < other
            //   0 is this == other
            //     > 0 if this > other
            return this.WoofPower - other.WoofPower;
        }
    }

Using Dog:

            Dog fido = new Dog("Fido", 4);
            Dog bowser = new Dog("Bowser", 9);

            int compare = fido.CompareTo(bowser);
Advertisement

#1,041 – Adding New Type Parameters when You Derive from a Generic Class

You can define a generic class that inherits from another generic class, for example:

public class ListPlus<T> : List<T>

You can also add new type parameters in the new class being defined.  In the example below, ListPlus derives from List<T> and adds a second type parameter.

        public class ListPlus<T, TShadow> : List<T>
        {
            private List<TShadow> shadowList = new List<TShadow>();

            public void AddItem(T mainItem, TShadow shadowItem)
            {
                base.Add(mainItem);
                shadowList.Add(shadowItem);
            }
        }

When we construct the type, we need to provide type arguments for both type parameters.

            ListPlus<Dog, Cat> myListPlus = new ListPlus<Dog, Cat>();
            Dog fido = new Dog("Fido");
            Cat puff = new Cat("Puff");
            myListPlus.AddItem(fido, puff);

#1,040 – Deriving from a Constructed Type

You can define a generic class that inherits from another generic class, for example:

public class ListPlus<T> : List<T>

You can also derive from a constructed type, rather than a generic type.  A constructed type is just a generic type with the type parameters filled in (type arguments provided).

For example:

    public class DogListPlus : List<Dog>
    {
        public void AddTwoDogs(Dog d1, Dog d2)
        {
            base.Add(d1);
            base.Add(d2);
        }
    }

We can then use this new type as follows:

            DogListPlus dogList = new DogListPlus();
            Dog fido = new Dog("Fido");
            Dog bowser = new Dog("Bowser");
            dogList.AddTwoDogs(fido, bowser);

#1,039 – Deriving from a Generic Class

A generic class includes one or more type parameters, allowing you to later declare a variable using a constructed type by specifying type arguments for each type parameter.

If you have an existing generic class, you can define a new class that inherits from the generic class.

Assume that we have a List<T> type, i.e. we can construct the type as follows:

            List<int> someInts = new List<int>();

We can also define a new class that inherits from List<T> and makes use of its type parameter as follows:

    public class ListPlus<T> : List<T>
    {
        public void AddTwoItems(T thing1, T thing2)
        {
            base.Add(thing1);
            base.Add(thing2);
        }
    }

We can now construct the new type by providing a type argument.

            ListPlus<Dog> dogs = new ListPlus<Dog>();
            Dog fido = new Dog("Fido");
            Dog bowser = new Dog("Bowser");
            dogs.AddTwoItems(fido, bowser);

#819 – A Private Constructor May Prevent Inheritance

You can make a constructor private to restrict creation of an instance of the class only to code within the class.

If all constructors in a class are private, this means that a derived class is also prevented from calling a constructor.  Because the derived class must be able to call some constructor on the parent class, this will effectively prevent the creation of any derived class.

Assume that a Dog class defines a single constructor and makes it private.  In the code shown below, the Terrier class defines a constructor, which would implicitly call the default constructor in the base class.  Because that constructor is private, we get a compiler error and can’t create the Terrier class.

    public class Terrier : Dog
    {
        public double FeistyFactor { get; set; }

        public Terrier(string name, int age, double feistyFactor)
        {
            Name = name;
            Age = age;
            FeistyFactor = feistyFactor;
        }
    }

819-001

#752 – C# Does Not Support Multiple Inheritance

Some other object-oriented languages, like C++ and Python, support multiple inheritance.  Multiple inheritance allows a class to inherit data and behavior from more than one parent class.

C#, on the other hand, does not support multiple inheritance.  Every class inherits from exactly one class.  Multiple inheritance can lead to certain problems in object-oriented languages.  (E.g. the “diamond problem“).  C# avoids these problems by supporting only single inheritance.

While a class in C# can only inherit from a single base class, it can implement a number of different interfaces.

#751 – Inheritance Only Partially Preserves Encapsulation

It can be argued that inheritance breaks encapsulation, since there is a tight coupling between the parent and child classes and because the child class can override behavior in the parent class.

But inheritance does partially preserve encapsulation, with respect to private members of the base class.

  • An instance of the child class can’t access private members in the base class
  • The implementation of the child class can’t access private members in the base class

Assume that we have a Dog class with a private field barkCount and a Terrier class that derives from Dog.

            Terrier t = new Terrier();

            // ERROR: Dog.barkCount inaccessible due to its protection level
            int i = t.barkCount;

Also:

    public class Terrier : Dog
    {
        public void Test()
        {
            Console.WriteLine("Terrier " + Name);

            // ERROR: Dog.barkCount inaccessible due to its protection level
            int i = this.barkCount;
        }
    }

#744 – The Purpose of Inheritance

Inheritance in C# (and .NET) is the idea of designing a class that reuses the implementation of an existing class.

The primary purpose of inheritance is to reuse code from an existing class.  Inheritance allows you to create a new class that starts off by including all data and implementation details of the base class.  You can then extend the derived class, to add data or behavior.

You can also use inheritance to modify the behavior of an existing class.  The code below shows a QuietDog class that does everything that a normal Dog does, but barks quietly.

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

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

        public void Fetch()
        {
            Console.WriteLine("Fetching !");
        }
    }

    public class QuietDog : Dog
    {
        public new void Bark()
        {
            Console.WriteLine(".. silence ..");
        }
    }

#742 – A Simple Example of Inheritance

Here’s a simple example of inheritance in C#.

The Dog class has a Name property and a Bark method.

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

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

The Terrier class inherits from Dog and adds a HuntVermin method.

    public class Terrier : Dog
    {
        public void HuntVermin()
        {
            Console.WriteLine(Name + " off to find vermin");
        }
    }

An object of type Dog has access to the Name property and the Bark method.  An object of type Terrier also has access to Name and Bark and also to the HuntVermin method.

            Dog d = new Dog();
            d.Name = "Kirby";
            d.Bark();

            Terrier t = new Terrier();
            t.Name = "Jack";
            t.Bark();
            t.HuntVermin();

742-001

#741 – The Basics of Inheritance

Inheritance in C# (and .NET) is the idea of designing a class that reuses the implementation of an existing class.  All public members in the original (parent) class become public members in the new (child) class.  (Except for constructors).  Both data and behavior are inherited by the child class.

Every class in C# must inherit from exactly one class.  By default, a class inherits from System.Object.  You can instead indicate the desired parent class by specifying it after a colon (:) when defining the new class.

public class Terrier : Dog
{
}

The class being inherited from is known as the base class or parent class.  The new class is known as the derived class or child class.

An instance of the child class automatically has access to all public members of the base class, as well as its own public members.