Click here to Skip to main content
Click here to Skip to main content
Go to top

Getting Closer to Multiple Inheritance in C# 3.0

, 13 May 2008
Rate this:
Please Sign up or sign in to vote.
How to implement multiple inheritance in C# 3.0

Introduction

Many people out there may not be impressed or happy about this, but yes, there is a way to simulate multiple inheritance in C# 3.0. And more importantly, it is incredibly simple to implement.

Using the Code

All you require is an interface to use as a marker and some extension methods.

Here, we have the simplest of scenarios, a Logger “class” that any class can “inherit” from.

public interface Logger
{
}
public static class LoggerImpl
{
    public static void Log(this Logger instance, string msg)
    {
        Debug.WriteLine(msg);
    }
    public static void LogError(this Logger instance, string msg)
    {
        Debug.WriteLine(string.Format("ERROR: {0}", msg));
    }
}

Figure 1. Implementation using the Interface and Extension methods.

public partial class Form1 : Form, Logger
{
    private void button1_Click(object sender, EventArgs e)
    {
        this.Log("Button1 Clicked");
    }
    private void button2_Click(object sender, EventArgs e)
    {
        this.LogError("Button2 Clicked");
    }
}

Figure 2. WinForm usage.

public class Car: Vehicle, Logger
{
    private override void Drive()
    {
        this.Log("I’m driving now!");
    }
} 

Figure 3. Business Object usage.

I don't believe it can get any easier than this. Obviously, you can get much more complex and sophisticated as the solution necessitates. The key is to understand the new feature of C# 3.0, extension methods. I won't go into the specific of this C# feature as it is well documented in many places.

There is one caveat to the implementation which is that you must use the 'this' keyword to access the extension methods from within the class itself. Not a hefty price to pay for this feature.

Points of Interest

As a further example, I've used this approach in ASP.NET for a custom Session handler class (SessionSupport) which leverages generics, constraints and lambdas to manage a specific type of business object derivative. This particular implementation is also aware of the fact that the SessionSupport class is always applied to ASP.NET Page classes and therefore can safely cast the ‘this’ instance parameter to a Page type and access all of the Page specific members. I opted to document this feature using a basic Logger sample to keep things as focused on the issue at hand as possible.

Another approach would be to include a few methods on the interface forcing the consumer base class to implement these functions providing some access to pertinent fields, properties, or methods of the base class and avoiding the blind cast.

Follow Up

I suppose the simplicity of the example has worked against me. Smile | :)

In this situation, assuming you wanted every class to expose the Logging methods, as Patrik_J points out, which isn't unreasonable, you could simply add the extension methods to the 'object' class. But that misses the point of the demonstration - my bad.

The ASP.NET Session code that I've applied this technique to is far too complex (and proprietary) for this forum, but I can try to give another example of the usage.

Let’s say, for example, that you want to have an automated security feature that could be applied to a subset of selected Windows controls in a WinForms application.

For example:

public class MyForm : Form, SecurityMgr
{
...
}


The problem is as such; you want a method exposed from certain custom controls called ‘ApplySecurity’ which takes a security token and dynamically enables/disables child controls contained on it. I won't go into the details of how the tokens and controls are related. I'll leave that for another day. You have classes derived from System.Windows.Forms.Form and from System.Windows.Forms.ToolStripContainer and other classes that are derivatives of System.Windows.Forms.Control which contains the Controls property. You obviously don't want to derive a class from Form and from ToolStripContainer and from those others, simply to embed the new method. And then derive your custom Controls from it. Nor would you want to implement ‘ApplySecurity’ as an extension method on all System.Windows.Forms.Control as other classes have no context for this usage. So, at this point, you can apply this pattern.

I hope this adds some clarity to the benefits of this technique.

Polymorphism Addressed - Kinda Short

public interface Logger2 : Logger
{
}

public static class Logger2Impl
{
    public static void LogError(this Logger2 logger, string msg)
    {
        System.Diagnostics.Debug.WriteLine(string.Format("NEW ERROR: {0}", msg));
    }
}

I've made an attempt to address the polymorphism issue that was mentioned by Nick Darnell.

This solution still needs some thought - but it immediately interested me as it allows for reuse of the 'overridden' method. The code is again fairly straight forward and I'm using the simplest of scenarios to illustrate the point. By simply inheriting a new interface from the existing interface and 'overriding' the method of interest, you can mimic the desired behavior. Now all that is left is to switch your consumer class to derive from Logger2 rather than Logger and you can leverage this custom implementation in other classes (the additional benefit of interest). The actual code in the consumer class or the consumer of the consumer class invokes the LogError and Log methods in the appropriate base/derived classes (LogError in Logger2Impl and Log in LoggerImpl) without knowing the difference.

History

  • 13th May, 2008: Initial post

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication

Share

About the Author

Audaxis
Architect
United States United States
No Biography provided

Comments and Discussions

 
GeneralMy vote of 3 PinmemberNick Alexeev19-Sep-14 13:46 
GeneralNot impressed (feedback) PinmemberOleg Shilo26-May-08 14:30 
GeneralAwfully clever. PinmemberAshaman15-May-08 10:08 
GeneralHere's a bone...=) PinmemberMember 345750613-May-08 10:40 
GeneralRe: Here's a bone...=) PinmemberShane Battrick13-May-08 12:02 
QuestionWhat do you win? PinmemberPatric_J13-May-08 9:06 
AnswerRe: What do you win? PinmemberShane Battrick13-May-08 10:28 
GeneralNot impressed PinmemberNick Darnell13-May-08 7:33 
GeneralRe: Not impressed PinmemberShane Battrick13-May-08 8:18 
GeneralRe: Not impressed PinmemberShane Battrick13-May-08 11:48 
GeneralRe: Not impressed PinmemberNick Darnell13-May-08 12:41 
GeneralRe: Not impressed PinmemberShane Battrick13-May-08 13:56 
GeneralRe: Not impressed PinmemberNick Darnell13-May-08 15:19 
GeneralRe: Not impressed PinmemberShane Battrick13-May-08 16:11 
GeneralRe: Not impressed PinmemberS. Senthil Kumar13-May-08 21:28 
GeneralRe: Not impressed PinmemberttuBrant18-May-09 19:44 

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

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

| Advertise | Privacy | Mobile
Web02 | 2.8.140926.1 | Last Updated 13 May 2008
Article Copyright 2008 by Audaxis
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid