Click here to Skip to main content
15,867,325 members
Articles / Mobile Apps

Simulated Multiple Inheritance Pattern for C#

Rate me:
Please Sign up or sign in to vote.
4.63/5 (54 votes)
9 Apr 2005CPOL8 min read 434.1K   1.3K   112   49
Design pattern for simulating multiple inheritance in C#.

Introduction

There are situations where multiple inheritance is the best (if not the only) choice when designing a certain model for our program or project. C# unfortunately does not support multiple inheritance and so we must look for ways to adapt our design to make possible its implementation. But C# does offer resources and tricks that can be used to simulate multiple inheritance without radically redesigning our class model, with only adding several auxiliary methods and classes and taking one or two precautions while coding them. I propose a design pattern that lets us simulate multiple inheritance in a C# program in a way that produces classes that behave almost like they were really extended from two or more parent classes. We will face classical multiple inheritance problems too and will see how to address them.

Background

Most recent languages like C#, Java, Delphi, have simple inheritance. They don't have multiple inheritance because their designers had to choose between have it in and have all the problems it comes with, or get it out of the language putting away all those problems, and introduce a versatile and less problematic substitute like interfaces and interface inheritance. Multiple inheritance has multiple problems that we will discuss later. But those problems are quite pathological and do not arise in any program in which multiple inheritance could be useful or could be the most appropriate design.

There are traditional ways to emulate multiple inheritance with interface inheritance with more or less success. Let's suppose we have two classes, A and B, and we want C to inherit from both of them.

Image 1

C#
class A
{
    m1();
}

class B
{
    m2();
}

class C : A, B
{
    m1();
    m2();
}

That code is impossible in C#. The following is the classical workaround to deal with this:

Image 2

C#
class A
{
    m1();
}

interface IB
{
    m2();
}

class B : IB
{
    m2();
}

class C : A, IB
{
    B BObject;
    m1();
    m2() { BObject.m2(); }
}

In this code, we make class B to implement a new interface named IB that has identical methods as those of B. Then class C inherits from A and IB, and uses an internal B object that replicates B's m2 method implementation. So C.m2 in fact calls its BObject.m2 method. Then we can say C now has A's implementation of m1() and B's implementation of m2(). And we can use C object wherever we could use A objects or IB objects.

But this solution has several problems. One of them is the fact that we can't use C objects where explicitly B objects are expected, but only where IB objects are. So maybe we will have to change all the other code in the project, replacing references to B objects with references to IB objects. That will not be a big problem if we are designing the model and can take such decisions. But if the project is dependant on third party code or the standard library (the Framework) then we will be unable to make those modifications. Even more important, if class B is not ours, but it is from the standard library or from third party code, we can't make it implement our IB interface. We can't touch it.

The simulated multiple inheritance pattern for C#

We have seen that we cannot simulate multiple inheritance completely using only interfaces and simple inheritance. We need something more, and C# happens to have that. Let's see.

We have these objectives:

  • We want class C to inherit from classes A and B, being able to call their implementation of their methods with no need to rewrite them.
  • We want to be able to use C objects wherever an A object or B object is expected.
  • We don't want to modify A or B, for they are untouchable for one or another reason, or we simply don't care.
  • We want to instantiate, reference, and use C objects just like normal objects.
  • We work with parent classes that don't expose public fields, but use properties instead. However, this pattern will work even if one of the parent classes (at most) exposes public fields.
  • Of course, this pattern works for three or more parents, not only two.

Here is the basic idea:

We will create two auxiliary classes, Aaux and Baux that inherit from A and B respectively.

C#
class A
{
    m1();
}

class B
{
    m2();
}

class Aaux : A
{
    m1();
}

class Baux : B
{
    m2();    
}

Our new class C won't inherit from A or B but have the same methods of both of them. Besides, it will contain two objects: one of type Aaux and the other of type Baux. We will call them C.APart and C.BPart respectively. C will use their implementations of m1 and m2 instead of rewriting them.

C#
class C
{
    Aaux APart;
    Baux BPart;
    
    m1()
    {
        APart.m1();
    }
    m2()
    {
        BPart.m2();
    }
}

So every C object has a pair of A and B objects inside. Let's make those objects know who is containing them by adding a reference to the C object that contains them. We will modify classes Aaux and Baux for this purpose:

C#
class Aaux : A
{
    C CPart;
    
    m1();
}

class Baux : B
{
    C CPart;
    
    m2();
}

And finally we arrive at the final trick. We will redefine the implicit casting operator for class C, so:

  • Whenever an A object is expected and a C object is found, C.APart is returned.
  • Whenever a B object is expected and a C object is found, C.BPart is returned.

Again, we will redefine the implicit casting operator for class Aaux so whenever a C object is expected and an Aaux object is found, Aaux.CPart is returned. Identically, we will redefine the implicit casting operator for class Baux so whenever a C object is expected and a Baux object is found, Baux.CPart is returned.

This is the final look:

Image 3

C#
class Aaux : A
{
    C CPart;
    
    m1();
    
    static implicit operator C(Aaux a)
    {
        return a.CPart;
    }
}

class Baux : B
{
    C CPart;
    
    m2();

    static implicit operator C(Baux b)
    {
        return b.CPart;
    }
}

class C
{
    Aaux APart;
    Baux BPart;
    
    m1()
    {
        APart.m1();
    }
    m2()
    {
        BPart.m2();
    }

    static implicit operator A(C c)
    {
        return c.APart;
    }
    static implicit operator B(C c)
    {
        return c.BPart;
    }
}

Now given that code, we can use C objects wherever an A or B object is expected, in addition to where a C object is expected. The only cost has been adding two extra classes and requiring the parent classes not to expose public fields.

However, there is another step we can take that will allow us to reduce in on the number of extra classes required and will let one of the parent classes have public fields. In fact, the class diagram will be even simpler.

Image 4

We only have to make C inherit directly from A, the class which exposes public fields.

Of course, properties are fully compatible with this pattern, since they behave like methods. So parent classes may have as many public properties as they wish.

Using the code

Let's see an example. We are a computer dealer that buys computer hardware from major vendors and sells it to end users. However, we often get out of stock and we avoid losing customers by buying from rival computer shops and re-selling to our customers. We are not the only ones with that policy, so other shops often purchase our goods for selling them later. Our program has two arrays - in one of them we keep all our vendors, and in the other we keep all our customers. Rival shops are both vendors and customers. This would be the idea:

C#
class Vendor
{...}
class Customer
{...}
class Shop : Vendor, Customer
{...}

And this could be the final code (it's available in the download):

C#
/// <summary>

/// A computer manufacturer. They resupply us.
/// </summary>

public class Vendor
{
    string id;
    public string VendorId
    {
        get
        {
            return id;
        }
        set
        {
            id = value;
        }
    }

    public Vendor(string vendorId)
    {
        id = vendorId;
    }

    public virtual void AskForRessuply()
    {
        Console.WriteLine("Please ressuply me, vendor "+id+".");
    }
}

/// <summary>

/// A customer. We send them their purchased goods.
/// </summary>

public class Customer
{
    string name;
    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
    }

    public Customer(string customerName)
    {
        name = customerName;
    }

    public virtual void SendOrder()
    {
        Console.WriteLine("Dear "+name+": We are sending your goods.");
    }
}


/// <summary>

/// The auxiliary class that redefines Customer.
/// </summary>

internal class CustomerAux : Customer
{
    // <--- It has a link to the Shop object that contains it.
    internal Shop shopPart;

    internal CustomerAux(string customerName) : base (customerName)
    {
    }

    // We declare the implicit casting operator for returning
    // shopPart when a Shop object is expected.
    static public implicit operator Shop(CustomerAux c)
    {
        return c.shopPart;
    }
}


/// <summary>

/// We consider a shop like a Vendor and a Customer,
/// for we both ask them to resupply us,
/// or they purchase our goods.
/// </summary>

public class Shop : Vendor        // <-- It inheirs only from Vendor...
{
    CustomerAux customerPart;    // ...but has a CustomerAux object inside.

    // Shops have an address in addition to the vendor id
    // and the customer name inherited from Vendor and Customer.
    string address;
    public string Address
    {
        get
        {
            return address;
        }
        set
        {
            address = value;
        }
    }
    // Here we are 'redirecting' property Name to the customerPart object.
    public string Name
    {
        get
        {
            return customerPart.Name;
        }
        set
        {
            customerPart.Name = value;
        }
    }

    // The Shop constructor.
    public Shop(string vendorId, string customerName, string shopAddress) :
                                                              base (vendorId)
    {
        // We create and bind the CustomerAux object to this one.
        customerPart = new CustomerAux(customerName);
        customerPart.shopPart = this;

        address = shopAddress;
    }

    // Here we are redirecting Customer.SendOrder to the customerPart object.
    public virtual void SendOrder()
    {
        customerPart.SendOrder();
    }

    // We redefine the implicit casting operator for returning
    // customerPart when a Customer object is expected.
    static public implicit operator Customer(Shop s)
    {
        return s.customerPart;
    }

}

// An example of use of the Vendor, Customer and Shop classes.
class EntryPoint
{
    static void Main(string[] args)
    {
        Vendor ibm = new Vendor("32FK-IBM");
        Vendor hp = new Vendor("1138-HP");
        Customer mrSimpson = new Customer("Mr. Simpson");
        Customer mrGates = new Customer("Mr. Gates");
        Shop joys =
          new Shop("1979-JCS", "Joy's Computer Shop", "123, Fake St.");

        Vendor[] vendors = {ibm, hp, joys};
        foreach(Vendor ven in vendors)
            ven.AskForRessuply();

        Customer[] customers = {mrSimpson, mrGates, joys};
        foreach(Customer cus in customers)
            cus.SendOrder();
        Console.ReadLine();
    }
}

Points of interest - classical problems

One of the most important problems of multiple inheritance is caused by this situation:

Image 5

Class A has the m1() method. The [ImpA] means that method m1 has been implemented in A. Classes B and C inherit from A, and both of them redefine method m1. So class B has its own implementation of m1, denoted by [ImpB], and class C has its own implementation of m1 too, denoted by [ImpC].

Now class D inherits from B and C. The problem is... what implementation of m1 is used while running this code?

C#
D d = new D();
d.m1();

...this code?

C#
B d = new D();
d.m1();

...and this code?

C#
C d = new D();
d.m1();

Languages and compilers supporting multiple inheritance solve this in one way or the other. But this makes compiling, debugging and understanding the code more difficult. Often the version of the implementation of m1 to be run is nearly unpredictable.

However, this pattern solves to certain degree that problem, because we can choose what implementation will be run. Assuming our D class uses our pattern for simulating multiple inheritance, there will be five different situations:

  • D redefines m1 and we always want its implementation to be used: We just have to make D.BPart.m1() and D.CPart.m1() to call D.m1().
  • We always want B's implementation: Then we make D.m1() and D.CPart.m1() call D.BPart.m1().
  • We always want C's implementation: Then we make D.m1() and D.BPart.m1() call D.CPart.m1().
  • We want B's implementation when m1 is called from a B type variable, C's implementation when m1 is called from a C type variable, and D's new implementation when called from a D type variable: Just redefine m1 in D class and let D.BPart and D.CPart alone. (This option is not recommendable except when we know what we are doing.)
  • We want three new different implementations depending on the type of the variable that references our D object at call time: We write different implementations of m1 in D.m1(), D.BPart.m1(), and D.CPart.m1(). (This is even less recommendable than the previous one. But it could be useful for someone.)

Last comment

Multiple inheritance was not included in C# for important reasons. However, I sometimes miss it and that is the reason why I proposed this pattern. I think it may be useful for those who find more advantages in its application than disadvantages. I'd like to see your comments on it, telling problems I didn't see and advices for enhancement.

History

  • April 9th, 2005: First version of this article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Spain Spain
Computer Science Engineering student.
University of Murcia, Spain

Comments and Discussions

 
PraiseThumbs up Pin
Alan Klette10-Jul-17 17:45
Alan Klette10-Jul-17 17:45 
Questionhéritage Multiple avec ASP.NET C# Pin
Member 1155787626-Mar-15 5:13
Member 1155787626-Mar-15 5:13 
Question[My vote of 1] This is composition! Pin
Mauro Sampietro11-Dec-14 21:52
Mauro Sampietro11-Dec-14 21:52 
GeneralMy vote of 3 Pin
Marcelo Lujan [El Bebe.Net ]22-Mar-12 14:18
Marcelo Lujan [El Bebe.Net ]22-Mar-12 14:18 
GeneralMy vote of 1 Pin
Cloud Hsu27-Jun-10 0:09
Cloud Hsu27-Jun-10 0:09 
GeneralRe: My vote of 1 Pin
Sergey Alexandrovich Kryukov9-Jan-12 8:51
mvaSergey Alexandrovich Kryukov9-Jan-12 8:51 
QuestionGreat Article - Can this pattern be used to inherit from two .Net library classes? Pin
Mohammed Habeeb26-Apr-10 3:05
Mohammed Habeeb26-Apr-10 3:05 
GeneralErrors Pin
Rudedog227-May-09 5:43
Rudedog227-May-09 5:43 
GeneralRe: Errors Pin
David Esparza-Guerrero27-May-09 8:33
David Esparza-Guerrero27-May-09 8:33 
GeneralRe: Errors Pin
VikasAgarwal8417-Sep-11 8:43
VikasAgarwal8417-Sep-11 8:43 
GeneralSee Eiffel for a better paradigm Pin
MurphTheGreat4-Jul-07 18:37
MurphTheGreat4-Jul-07 18:37 
GeneralI said it once and I will say it again PinPopular
icestatue14-Feb-06 1:47
icestatue14-Feb-06 1:47 
GeneralGood Idea. But have to be careful Pin
Salil Pitkar3-Dec-05 7:32
Salil Pitkar3-Dec-05 7:32 
GeneralProblem... Pin
fcuesta18-Oct-05 4:00
fcuesta18-Oct-05 4:00 
GeneralRe: Problem... Pin
David Esparza-Guerrero3-Dec-05 8:22
David Esparza-Guerrero3-Dec-05 8:22 
GeneralRe: Problem... Pin
tekcode29-Sep-09 7:53
tekcode29-Sep-09 7:53 
QuestionMultiple inheritance with built in classes Pin
Snews10-Oct-05 1:22
Snews10-Oct-05 1:22 
AnswerRe: Multiple inheritance with built in classes Pin
David Esparza-Guerrero10-Oct-05 5:18
David Esparza-Guerrero10-Oct-05 5:18 
GeneralExcellent Pin
Nigel Shaw3-May-05 9:16
Nigel Shaw3-May-05 9:16 
QuestionWhy Baux? Pin
Paolo Martinoli15-Apr-05 4:16
professionalPaolo Martinoli15-Apr-05 4:16 
AnswerRe: Why Baux? Pin
David Esparza-Guerrero15-Apr-05 7:14
David Esparza-Guerrero15-Apr-05 7:14 
GeneralRe: Why Baux? Pin
Paolo Martinoli18-Apr-05 6:20
professionalPaolo Martinoli18-Apr-05 6:20 
GeneralRe: Why Baux? Pin
David Esparza-Guerrero18-Apr-05 8:10
David Esparza-Guerrero18-Apr-05 8:10 
GeneralRe: Why Baux? Pin
Paolo Martinoli20-Apr-05 5:55
professionalPaolo Martinoli20-Apr-05 5:55 
GeneralRe: Why Baux? Pin
David Esparza-Guerrero20-Apr-05 9:09
David Esparza-Guerrero20-Apr-05 9:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.