Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with Lack of Multiple Inheritance in C#

I am working on a mini-framework for "runnable" things. (They are experiments, tests, tasks, etc.)

// Something that "runs" (in some coordinated way) multiple "runnable" things.
interface IRunnableOf<T> where : IRunnable

// Provide base-class functionality for a "runner"
abstract class RunnerBase<T> : IRunnableOf<T>


class SequentialRunner<T> : RunnerBase<T>  // Same interface, different behavior.
class ConcurrentRunner<T> : RunnerBase<T>
// other types of runners.

class ConcurrentBlockRunner : SequentialRunner<Block>
class SequentialBlockRunner : ConcurrentRunner<Block>

Now, how can I reconcile ConcurrentBlockRunner and SequentialBlockRunner? By this I mean:

  1. Refer to them by a common ancestor, for use in a collection. (IEnuerable<T> where T = ??)

  2. Provide additional base class functionality. (Add a property, for example).


I remedied #1 by adding another interface that just specified a type parameter to IA<T>:

interface IBlockRunner : IRunnableOf<Block> { }

And modified my ConcurrentBlockRunner and SequentialBlockRunner definitions to be:

class ConcurrentBlockRunner : SequentialRunner<Block>, IBlockRunner
class SequentialBlockRunner : ConcurrentRunner<Block>, IBlockRunner

Since ConcurrentBlockRunner and SequentialBlockRunner both use Block for their type parameter, this seems to be a correct solution. However, I can't help but feel "weird" about it, because well, I just tacked that interface on.


For #2, I want to add a couple pieces of common data to ConcurrentBlockRunner and SequentialBlockRunner. There are several properties that apply to them, but not to their only common base class, which is all the way up at RunnerBase<T>.

This is the first time while using C# that I've felt multiple inheritance would help. If I could do:

abstract class BlockRunnerBase {
   int Prop1 { get; set; }
   int Prop2 { get; set; }

class ConcurrentBlockRunner : SequentialRunner<Block>, BlockRunnerBase
class SequentialBlockRunner : ConcurrentRunner<Block>, BlockRunnerBase

Then I could simply add these extra properties to BlockRunnerBase, and everything would just work. Is there a better way?


I know I will be recommended immediately to consider composition, which I began to work with:

class BlockRunner : IBlockRunner  {
   IBlockRunner _member;

   int Prop1 { get; set; }    // Wish I could put these in some base class
   int Prop2 { get; set; }       

   // Lots of proxy calls, and proxy events into _member
   void Method() { _member.Method(); }
   event SomeEvent
   {
      add { _member.SomeEvent += value; }
      remove { _member.SomeEvent -= value; }
   }
}

The problem I encountered (driving me to write this question) was that once you compose, you lose type compatibility. In my case, _member was firing an event, so the sender parameter was of type SequentialBlockRunner. However, the event handler was trying to cast it to type BlockRunner, which of course failed. The solution there is not use add/remove to proxy the events, but actually handle them, and raise an event of my own. So much work just to add a couple properties...

like image 207
Jonathon Reinhart Avatar asked Jun 11 '12 23:06

Jonathon Reinhart


People also ask

How do you handle multiple inheritance?

The only way to implement multiple inheritance is to implement multiple interfaces in a class. In java, one class can implements two or more interfaces. This also does not cause any ambiguity because all methods declared in interfaces are implemented in class.

What is alternative for multiple inheritance?

Composition and Interface Inheritance are the usual alternatives to classical multiple inheritance. Everything that you described above that starts with the word "can" is a capability that can be represented with an interface, as in ICanBuild , or ICanFarm .

Why is multilevel inheritance not supported in C?

C# does not support multiple inheritance , because they reasoned that adding multiple inheritance added too much complexity to C# while providing too little benefit. In C#, the classes are only allowed to inherit from a single parent class, which is called single inheritance .

Why multiple inheritance is not a good idea?

Allowing multiple inheritance makes the rules about function overloads and virtual dispatch decidedly more tricky, as well as the language implementation around object layouts. These impact language designers/implementors quite a bit and raise the already high bar to get a language done, stable, and adopted.


2 Answers

Composition over Inheritance, FTW!

To be more explicit:

class SequentialRunner<T> : RunnerBase<T>

should implement IRunnableOf<T> and proxy the RunnerBase<T> without inheriting it.

class SequentialRunner<T> : IRunnableOf<T>
{
   private readonly RunnerBase<T> _runnerBase;

   ...
}
like image 114
bluevector Avatar answered Oct 13 '22 14:10

bluevector


You can use extension methods to create mixin-like constructs, even with property-like elements.

I've also created an experiment with trait-like constructs in C#, NRoles.

But, all of these require non-standard coding, and will not be ideal for APIs that are meant to be exposed to third parties. I think you should try to rearrange your classes and use composition with delegation using interfaces if possible.

like image 40
Jordão Avatar answered Oct 13 '22 13:10

Jordão