4

I know that C# does not offer multiple inheritance. And I know there' are workarounds like this one for instance.

But here's a problem that I faced today, can't figure any ELEGANT workaround. I'll add some abstract code-sample so you get it quicker...

(let it be a real-life ASP.NET code - cause those "class A, class B" code-samples are really confusing):

public class AdminPage : System.Web.UI.Page
{
    protected override void OnInit(EventArgs e)
    {
        //if not an admin - get out
        if(!CurrentUserIsAdmin()) Response.End();

        base.OnInit (e);
    }
}

public class JQueryPage : System.Web.UI.Page
{
    protected override void OnInit(EventArgs e)
    {
        RegisterJQueryScript();
        base.OnLoad (e);
    }
}

//now here's what I REALLY miss in C#
public class AdminJQueryPage : AdminPage, JQueryPage;
Community
  • 1
  • 1
Alex from Jitbit
  • 53,710
  • 19
  • 160
  • 149

6 Answers6

9

Compose out the functionality? This is better for Single Responsibility. You'd have to think carefully about your constructors.

interface IAdminPage {
  public string AdminPageMethod();
}

interface IJQueryPage {
  public string JQueryPageMethod();
}

internal class AdminPage : IAdminpage {
  private string someString;

  internal AdminPage(string value) {
    this.someString = value;
  }

  public string AdminPageMethod() {
    return "AdminPage result with some string: " + this.someString;
  }
}

internal JQueryPage : IJQueryPage {
  private int someNumber;

  internal JQueryPage(int value) {
    this.someNumber = value;
  }

  public string JQueryPageMethod() {
    return "JQueryPage result with number: " + this.someNumber;
  }
}

class AdminJQueryPage : IQueryPage, IAdminpage {
  private readonly IAdminPage adminPage;
  private readonly IJQueryPage jqueryPage;

  public AdminJQueryPage(string someString, int someNumber) {
    this.adminPage = new AdminPage(someString);
    this.jqueryPage = new JQueryPage(someNumber);
  }

  public string AdminPageMethod() {
    return this.adminPage.AdminPageMethod();
  }

  public string JQueryPageMethod() {
    return this.adminPage.JQueryPageMethod();
  }
}

If you really want multiple inheritance, look at Scala's traits

Edit: added passing of constructor values to composed out classes. Also made the classes internal (cannot be accessed or constructed outside the assembly) because they are only ever constructed by the AdminJQueryPage class, which is the 'public-facing' class.

Joe
  • 46,419
  • 33
  • 155
  • 245
  • Composition is elegant and is a better alternative to multiple inheritance in a lot of cases. – Quibblesome Dec 04 '09 at 11:21
  • The thing is that one drived class overrides method A, other derived class overrides method B. So this answer does not help. – Alex from Jitbit Dec 10 '09 at 06:52
  • Yes but the question really is, do you actually want that? Or could you solve the problem better by decomposing the problem to separate objects? Often over-riding and deep inheritance hierarchies are not actually required. Why not just solve the problem of needing a new class with an entirely new `IAdminJQueryPage` class composing entirely new (or perhaps derived) `IAdminPage` and `IJQueryPage`? – Joe Dec 10 '09 at 08:03
3

I came from C++ too and dont miss it, especially since reading Refactoring [and using a non-OOTB tool for that].

You can use PostSharp to post process based on placing attributes on your AdminJQueryPage which would achieve the exact same effect.

Or you can Extract Method code into helper classes and call that (i.e., Joe's example)

Or you can put the helpers in a single base class and call from that.

Either way your code will be clearer.

It's only a matter of time before your mixins start overlapping, and then your general suite of techniques for managing that complexity needs to kick in - in C++, MI should only have been one tool in a suite - rather than a very sexy hammer.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
2

its possible to fake a mixin by specifying a interface and creating extension methods for that interface. however I'm not use this will help overriding methods, only adding new ones. you are of course able to then call an extension method when overriding, but that is basically the same as extracting the methods to a helper class, but with a little more sugar

jk.
  • 13,817
  • 5
  • 37
  • 50
2

Even if it was possible, one problem with the semantics of an MI-based solution to the specific problem you raised is what happens on the markup side? The Render() method that generates the markup would run first in one class, and then in the other? That's probably not the behavior you want when both classes generate entire pages.

If you're open to solutions that are outside of the language itself, there are several elegant options in ASP.NET that will address the type of issue you raised (changing the actions taken during an event in the page life cycle). For example:

  1. Page Adapters
  2. Control Adapters
  3. Custom user controls
  4. HttpModules
  5. Master Pages
  6. Tag mapping

The best choice will of course depend on the details of your application. In case it's helpful, I cover those options in my book, including sample code: Ultra-Fast ASP.NET.

RickNZ
  • 18,448
  • 3
  • 51
  • 66
  • clearly you'd want virtual MI here or looking at it the other way you just want to mixin the added behaviour and have a single System.Web.UI.Page base – jk. Dec 04 '09 at 11:34
  • Sure. I guess my point was that mixins != MI, which is what the OP asked about. – RickNZ Dec 04 '09 at 12:41
1

The simplest approach is to build a hierarchy - allow AdminPage to inherit from JQueryPage like so:

public class AdminPage : JQueryPage
{
    protected override void OnInit(EventArgs e)
    {
        //if not an admin - get out
        if(!CurrentUserIsAdmin()) Response.End();

        base.OnInit (e);
    }
}

public class JQueryPage : System.Web.UI.Page
{
    protected override void OnLoad(EventArgs e)
    {
        RegisterJQueryScript();
        base.OnLoad (e);
    }
}

//now here's what I REALLY miss in C#
public class AdminJQueryPage : AdminPage

My guess is some of this awkwardness comes from the ASP.NET page model, which uses overridden base class methods.

Jeremy McGee
  • 24,842
  • 10
  • 63
  • 95
  • Problem is that MI (and mixins) allows arbitrary selection of which services you want to mix in. He're you're hardwiring the sets. But if this works in the questioners context, it's obviosuly clean ans dimple. – Ruben Bartelink Dec 04 '09 at 11:05
0

You can to do this with Interfaces

    public interface IJQueryPage
    {
    }

    public abstract class AdminPage : System.Web.UI.Page
    {
        protected override void OnInit(EventArgs e)
        {
            //if not an admin - get out
            if(!CurrentUserIsAdmin()) Response.End();
            base.OnInit (e);
        }
        protected override void OnLoad(EventArgs e)
        {
            if (this is IJQueryPage)
            {
                RegisterJQueryScript();
            }            

            base.OnLoad (e);
        }
    }

    public class AdminJQueryPage : AdminPage, IJQueryPage
    { 
    }
Jan Remunda
  • 7,840
  • 8
  • 51
  • 60
  • It's generally a bad idea to use reflection in production code. All kinds of things can go wrong, maintenance and refactoring can be diffult and you lose the safety introduced by the type system. – Joe Dec 04 '09 at 11:07
  • Attributes are generally preferred to marker interfaces. But if you did want to do this, you'd say `if(this is IJQueryPage)` instead of `if (this.GetType().GetInterface("IJQueryPage") != null)`. Joe's example is a lot cleaner than this is going to end up though. – Ruben Bartelink Dec 04 '09 at 11:08
  • to Ruben: yes you're right. Probably i'm using reflection too much :-) I'll modify my answer. – Jan Remunda Dec 04 '09 at 14:25