Click here to Skip to main content
13,300,654 members (54,529 online)
Click here to Skip to main content
Add your own
alternative version


61 bookmarked
Posted 27 Mar 2008

Multiple Inheritance in C#

, 27 Mar 2008
Rate this:
Please Sign up or sign in to vote.
The attributes can be used to provide multiple inheritance functionality for C# classes


This article shows a possible way to implement multiple inheritance (MI) within the C# code. It is absolutely explicit by design and it lacks some of the classic MI problems such as inheritance ordering.


There are multiple ways to avoid or overcome the need for MI in C#. But sometimes, particularly for smaller projects (games, etc.), it would be more feasible to use its advantages. This was the case with my RL game. So I hope I found the way which should be reasonable and without being disturbed by the obstacles which native C# code puts in the way of multiple inheritance.

I don't consider multiple inheritance a good pattern of programming in general and it should be used only when the advantages of this pattern overweigh the disadvantages.

Class of Interest

First, we have to define our smart ancestor class which will handle all the functionality needed to implement MI. It is not much complicated. The missing inheritance will be compensated by the attribute MI.

using System;
using System.Collections.Generic;

namespace CSharpMultipleInheritance
    public class Ancestor : MarshalByRefObject

When a class inherited from the Ancestor class is created, the set of its custom attributes instances is gathered and saved into a dictionary. This hash will be later used to access the inherited properties (methods, etc.)

private readonly Dictionary<Type, Object> attributes = null;

public Dictionary<Type, Object> Attributes
    get { return attributes; }

public Ancestor()
    attributes = GetAttributes(GetType());

private Dictionary<Type, Object> GetAttributes(Type sourceType)
    Object[] collection = sourceType.GetCustomAttributes(true);
    Dictionary<Type, Object> result = new Dictionary<Type, Object>();

    foreach (Object attribute in collection)
        Type attributeType = attribute.GetType();

        if (result.ContainsKey(attributeType))
            throw new Exception(string.Format(
            STR_DupliciteAttributeFound, attributeType.Name, sourceType.Name));
            result.Add(attributeType, attribute);

    return result;

Them.. Methods

The Check method tests if a class is "inherited" from a specific attribute class. It's an equivalent of the native C# IS operator in our MI. As the code shows, it only checks whether the attribute type is present in the list of custom attributes.

public Boolean Check<TAttribute>()
return attributes.ContainsKey(typeof(TAttribute));

To determine whether an Ancestor inherited class contains all the attributes as the target type, that means yet another IS operator (this time a "real" one), the Is method is used. You need to supply a target Ancestor inherited class type to be checked against.

public Boolean Is<TAncestor>() where TAncestor : Ancestor
    Boolean result = true;
    Dictionary<Type, Object> sourceList = Attributes;
    Dictionary<Type, Object> destinationList = GetAttributes(typeof(TAncestor));

    foreach (KeyValuePair<Type, Object> destinationPair in destinationList)
        result = result && sourceList.ContainsKey(destinationPair.Key);

    return result;

The most important function which enables MI itself is the Use method. It retrieves the attribute class thus allowing to access its inner properties (methods, etc.).

public TAttribute Use<TAttribute>()
    if (Check<TAttribute>())
        return (TAttribute)attributes[typeof(TAttribute)];
        throw new ArgumentNullException(string.Format(
            STR_AttributeNotFound, typeof(TAttribute).Name, GetType().Name));

Examples of Use

I have chosen the classic Wikipedia example of multiple inheritance. A different example can be seen in the zipped files attached.

The attribute classes (future inheritable candidates) are defined as standard attributes. Only public fields (instead of private fields with public properties defined) are used in this article to keep it obvious.

So let have the two classes; the Person class which indicates a person's name and age and the Worker class which defines a worker's salary.

public class Person : Attribute
    public String Name;
    public Int32 Age;

public class Worker : Attribute
    public Double Sallary;

Now the attributes are assigned to our MI class. This class has to be inherited from the Ancestor class (defined above) to use its MI potential.

[Person, Worker]
public class Musician : Ancestor
    public String Name; // this can be used as a musician stage name

The parent classes are then accessed via the Ancestor's methods (Check, Is and Use) as shown in the following example:

static void Main()
    Musician bono = new Musician();

    bono.Use<Worker>().Name = "Bono";
    bono.Use<Person>().Name = "Paul David Hewson";
    bono.Use<Person>().Age = 47;
    if (bono.Is<Musician>()) Console.WriteLine("{0} is musician.", 
    if (bono.Check<Person>()) Console.WriteLine("His age is {0}", 

Possible Enhancement

  1. All the attribute classes used can have a common interface or can be inherited from a common attribute class to separate them from other non-MI attributes.
  2. The list of FieldInfo classes (PropertyInfo, etc.) can be cached across all the regular fields and also attribute fields to create an even more real MI.


  • The obvious limitation is that MI can't be used for the already inherited classes. I was trying to make the C# 3.0 extension methods which will be able to access any object. This proves to be impossible because there's no way of getting the custom attributes of a specific class instance from a general object.
  • Another limitation is that one "slot" of inheritance - the original C# one - is used. This should be compensated by MI itself.
  • An annoyance should be called the need to use method parenthesis for the MI methods. This is caused by the lack of the generic properties which are forbidden by C# design.
  • The compiler is unable to catch the inconsistencies in the Use<> class. This has to be handled by the Is<> checks or by the programmer himself/herself.


  • 2008-03-27: The generics were corrected in the article
  • 2008-03-26: The initial article was posted


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


About the Author

Smart K8
Software Developer
Czech Republic Czech Republic
Contacts: EMAIL -

You may also be interested in...


Comments and Discussions

GeneralNifty Pin
PIEBALDconsult27-Mar-08 6:25
memberPIEBALDconsult27-Mar-08 6:25 

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.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.171207.1 | Last Updated 27 Mar 2008
Article Copyright 2008 by Smart K8
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid