Inheritance

Inheritance

Generic and nongeneric classes can inherit a generic type. In addition, a generic type can be the base class to a generic or nongeneric type. Some basic rules apply. For example, the derived class cannot be a closed constructed type. Table 6-1 lists all the possible permutations.

Table 6-1: Inheritance Table for Generic Types

Base Class

Derived Class

Comments

Generic (open)

Generic (open)

Permitted when the derived class consumes the type parameters of the base class

Generic (open)

Generic (closed)

Not permitted

Generic (open)

Nongeneric

Permitted

Generic (closed)

Generic (open)

Permitted

Generic (closed)

Generic (closed)

Not permitted

Generic (closed)

Nongeneric

Not permitted

Nongeneric

Generic (closed)

Permitted

Nongeneric

Generic (open)

Not permitted

This sample code shows some of the permitted and not permitted combinations:

    public class ZClass<T> {
    }

    public class XClass<T> : ZClass<T> {
    }

    public class BClass<Y> {
    }

    public class AClass<Z> : BClass<int> {
    }

    public class YClass: ZClass<int> {
    }

    /*
    public class AClass<Z> : BClass<Y> {    [ illegal ]
    }

    public class YClass: ZClass<T> {        [ illegal ]
    }
    */

When inheriting an open constructed type, the constraints of the base class must be repeated in the derived type. Furthermore, the derived type can provide additional constraints on type parameters declared at the base type. This is not applicable to closed constructed types because closed constructed types do not have type parameters or constraints.

Here is sample code combining inheritance of generic types and constraints:

    public class ZClass<T> where T: IComparable {
    }

    public class YClass<T> : ZClass<T> where T: IComparable {
    }

    public class XClass<T> : ZClass<T> where T: IComparable, IDisposable {
    }

    public class BClass<Y> where Y: IEnumerable {
    }

    public class AClass<Z> : BClass<int[]> where Z:IDisposable {
    }

Overriding Methods

Methods that have a type parameter can be overridden, regardless of where the type parameter is declared. These methods can also override other methods. Table 6-2 lists the various combinations of overriding generic and nongeneric methods. If a base class is nongeneric or closed, overriding methods cannot have type parameters. Conversely, if the base class is open, overriding methods can employ type parameters.

Table 6-2: Combination of Overriding Generic Methods

Base Method

Derived Method

Comments

Nongeneric

Generic (open)

Permitted

Nongeneric

Generic (closed)

Permitted

Generic (open)

Nongeneric

Not permitted

Generic (open)

Generic (open)

Permitted; must use the same type parameters

Generic (open)

Generic (closed)

Not permitted

Generic (closed)

Nongeneric

Permitted

Generic (closed)

Generic (closed)

Permitted

Generic (closed)

Generic (open)

Not permitted

Here is some example code:

using System;

namespace Donis.CSharpBook{

    public class Starter{

        public static void Main(){
        }
    }

    public class ZClass<T> {
        public virtual void MethodA(T arg) {
        }
    }

    public class YClass<T> : ZClass<T>{
        public override void MethodA(T arg) {
        }

//      public override void MethodA(int arg) { [ illegal ]
//      }

    }

    public class XClass<X> : ZClass<int>{
        public override void MethodA(int arg) {
        }

//      public override void MethodA(X arg) { [ illegal ]
//      }

    }

    public class WClass: ZClass<int> {
        public override void MethodA(int arg) {
        }
    }
}

When a generic method overrides another generic method, it inherits the constraints of that method. The overriding method cannot change the inherited constraints.

The following code correctly overrides a generic method:

    public class ZClass {
        public virtual void MethodA<T>(T arg)
            where T: new() {
        }
    }

    public class YClass : ZClass {
        public override void MethodA<T>(T arg) {
            T obj=new T();
        }
    }

Nested Types

You can nest a generic type inside a nongeneric type. Conversely, a nongeneric type can be nested in a generic type. More intriguing is nesting generic types inside of generic types. The nested generic type can consume the type parameters of the surrounding type. A type parameter of the surrounding type cannot be redefined as a new type parameter in the nested type. However, the nested generic type can declare entirely new type parameters.

This is sample code of nested generic types:

using System;

namespace Donis.CSharpBook{
    public class Starter{
        public static void Main(){
            ZClass<int>.Nested<double> obj=
                new ZClass<int>.Nested<double>();
            obj.MethodA(10, 12.34);
        }
    }

    public class ZClass<T> {
        public void MethodA(T arg) {

        }

        public class Nested<S> {
            public void MethodA(T arg1, S arg2) {
                Console.WriteLine("arg1: {0}",
                    arg1.GetType().ToString());
                Console.WriteLine("arg2: {0}",
                    arg2.GetType().ToString());
            }
        }
    }
}