Simulating Multiple Inheritance in C#: Part II


Introduction

In the first part of this article, I showed how to effectively inherit public methods from additional parent classes. However, in the conclusion to that article I said there were a number of gaps in the implementation which I'd like to address in this second part.

Gaps in the implementation

OK, what are the areas still to be covered?

1. Child isn't really a Mother (no pun intended!). For example, we can't do any of these which would work if Child 'really' inherited from Mother:

A. Mother m = new Child();

B. Mother m = (Mother)new Child();

C. Mother m = new Child() as Mother;

D. If (c is Mother) Console.WriteLine("Child is a Mother")

2. We can't inherit protected methods.

3. If Mother inherited some interfaces, then Child would not automatically do so.

4. Having to change the name of the inherited version of Mother's MethodA to MethodD is not very satisfactory.

5. There is no way to tell by looking at the header of the Child class that it 'multiply inherits' Mother.

Of these, 1(a) and 1(b) are easy to deal with. All we need to do is provide overrides of the 'implicit' and 'explicit' operators in the Child class. However, this won't help with 1(c) and 1(d) which ignore custom conversions.
Suppose instead we implement an interface (IMother say) which has no members but is just a 'marker' interface. This would deal with 1(c) and 1(d) and also 5.

We can also deal with 2. quite easily because protected members are visible to our private nested class NMother which can then expose them (via a public member) to the Child class itself. Incidentally, this public member would not be accessible to classes other than Child because its accessibility is limited by the nested class itself being private.

3. can be addressed by including the interfaces in Child's implementation list - the members themselves will already be implemented.

Finally, 5.could be dealt with by adding those members whose names are duplicated to the IMother interface and then implementing them 'explicitly'. They could then be accessed using their original names via an IMother reference.

So, this gives us the following code:

using System;

interface IFace
{
    void MethodB();
}

class Father
{
    public void MethodA()
    {
        Console.WriteLine("Hello from Father's MethodA");
    }
}

class Mother : IFace // implements IFace
{
    public void MethodA()
    {
        Console.WriteLine("Hello from Mother's MethodA");
    }

    public void MethodB() // implements IFace.MethodB|
    {
        Console.WriteLine("Hello from Mother's MethodB");
    }

    public static void MethodS() // static method
    {
        Console.WriteLine("Hello from Mother's static MethodS");
    }

    public virtual void MethodV() // virtual method
    {
        Console.WriteLine("Hello from Mother's MethodV");
    }
 
    protected void MethodP() // Protected method
    {
        Console.WriteLine("Hello from Mother's protected MethodP");
    }
}

partial class Child : Father, IMother, IFace // implements IMother and IFace
{
    public void MethodC()
    {
        Console.WriteLine("Hello from Child's MethodC");
    }
}

partial class Child : Father, IMother, IFace // contains Mother inheritance stuff
{
    private NMother base2;
// contains NMother reference

    public Child()
    {
        base2 = new NMother();
        base2.Outer = this; // set NMother's Outer property
    }

    // private nested class which inherits from Mother
    private class NMother : Mother
    {
        // holds reference to outer Child object
        public Child Outer { get; set; }

        // overrides the virtual method Mother.MethodV
        public override void MethodV()
        {
            Console.WriteLine("Hello from Child's MethodV");
        }
 
        // exposes protected MethodP to outer Child
        public void MethodP_Expose()
        {
            MethodP();
        }
    }

    // wraps Mother.MethodB
    public void MethodB()
    {
        base2.MethodB();
    }

    // wraps static method Mother.MethodS
    public static void MethodS() // static method
    {
        NMother.MethodS();
    }

    // wraps override of Mother.MethodV|
    public virtual void MethodV()
    {
        base2.MethodV();
    }

    // wraps protected method Mother.MethodP and exposes it as public (not necessary)
    public void MethodP()
    {
        base2.MethodP_Expose();
    }

    // implicit conversion from Child to Mother
    public static implicit operator Mother(Child c)
    {
        return c.base2;
    }

    public static explicit operator Child(Mother m)
    {
        if (m is NMother)
        {
            return ((NMother)m).Outer;
        }
        else
        {
            string message = "Unable to cast object of type '" + m.GetType() + "' to  type 'Class' or a type derived therefrom.";
            throw new InvalidCastException(message);
        }
    }

    void IMother.MethodA() // explicitly implements IMother.MethodA
    {
        base2.MethodA();
    }
}

class GrandChild : Child
{
    // further overrides Mother.MethodV
    public override void MethodV()
    {
        Console.WriteLine("Hello from GrandChild's MethodV");
    }
}

interface IMother
{
    void MethodA(); // method with duplicated name
}

class Test
{
    static void Main()
    {
        Child c = new Child();
        c.MethodA();  // calls MethodA inherited from Father
        c.MethodB();
        c.MethodC();
        ((IMother)c).MethodA(); // calls MethodA inherited from Mother
        Child.MethodS();
        c.MethodV();
        c.MethodP();
        c = new GrandChild();
        c.MethodV();
        Mother m = new Child(); // implicit conversion
        m.MethodV();  // calls Child's version of MethodV      
        Child c2 = (Child)m; // explicit conversion
        c2.MethodV();  // calls Child's version of MethodV
        IMother im = new Child() as IMother;
        im.MethodA(); // calls Mother's MethodA
        if (c is IMother) ((IMother)c).MethodA(); // calls Mother's MethodA
        ((IFace)c).MethodB();// calls Mother's MethodB via an IFace reference        
        Console.ReadKey();
    }
}


When you build and run this code, the results should be:

Hello from Father's MethodA
Hello from Mother's MethodB
Hello from Child's MethodC
Hello from Mother's MethodA
Hello from Mother's static MethodS
Hello from Child's MethodV
Hello from Mother's protected MethodP
Hello from GrandChild's MethodV
Hello from Child's MethodV
Hello from Child's MethodV
Hello from Mother's MethodA
Hello from Mother's MethodA
Hello from Mother's MethodB

Conclusion

So we now have a reasonably complete implementation of multiple inheritance.

If we wanted another class (Child2 say) to 'multiply inherit' from Mother, then all we need to do is to copy the partial class with the Mother stuff in it to a partial class of Child2. Using partial classes in this way, enables us to keep everything together and facilitate code reuse.
 

Up Next
    Ebook Download
    View all
    Learn
    View all