Wednesday, August 29, 2012

Multiple inheritance with C#

It's not possible to do multiple inheritance in C#

public partial class A : FirstConcreteClass, SecondConcreteClass
{
}

public class FirstConcreteClass
{
 public void Hello()
 {
  Console.WriteLine ("Hello");
 }
}


public class SecondConcreteClass
{
 public void World()
 {
  Console.WriteLine ("World");
 }

 public string Yo()
 {
  return "POCO";
 }
}


But what you can possibly do is to isolate the SecondConcreteClass' APIs to an interface and implement it separately:


public class SecondConcreteClass : ISecondConcreteClass
{
 public void World()
 {
  Console.WriteLine ("World");
 }

 public string Yo()
 {
  return "POCO";
 }
}

public interface ISecondConcreteClass
{
 void World();
 string Yo();
}

Then change class A to this implementation, note the partial keyword and the implementation of ISecondConcreteClass:

public partial class A : FirstConcreteClass, ISecondConcreteClass
{
 public A()
 {
    this.SC = new SecondConcreteClass();
 }
}


The second piece of the puzzle. Put the stub class for ISecondConcreteClass implementation on a partial class. The stub class merely pass-the-buck the actions to the instance of ISecondConcreteClass.

public partial class A 
{
 ISecondConcreteClass SC { get; set; }
 
 public void World() { SC.World(); }
 public string Yo() { return SC.Yo(); }
}


To use:

var a = new A();
a.Hello();

a.World();
Console.WriteLine (a.Yo ());


Output:
Hello
World
POCO


The gist is, if you have a class(say B) that already extends another class and yet it need to extend another concrete class, just make that class B implement the other concrete's interface instead, and instantiate an object for the interface


public partial class B : WhateverClassThatMaybe, ISecondConcreteClass
{
 public B()
 {
    // instantiate SecondConcreteClass
    this.SC = new SecondConcreteClass();
 }
}


To shift the burden of manually coding the partial stub classes from the developer to the computer, use T4 (Text Template Transformation Toolkit) to automate the generation of those partial stub classes, that's how useful the computer is ツ


<#@ template language="C#v3.5" #>
  
  
<# var a = new[] { "A", "B" }; #>

namespace TestMultipleInheritance
{

<# foreach(string s in a) { #>

 public partial class <#=s#> 
 {
  ISecondConcreteClass SC { get; set; }
  
  public void World() { SC.World(); }
  public string Yo() { return SC.Yo(); }
 }


<# } #>


}


An aside, I'm using Mono .NET Framework version 4.0 and can use C# 4 features(e.g. dynamic), though for some reasons unknown to me, Mono's templating language is C# 3.5


The topic of OOP and inheritance is not complete without the capability to polymorph the object's functionality. So how can we achieve polymorphism with a simulated concrete class? In a normal class or abstract class, you have a virtual or abstract method that you can override. With multiple inheritance simulation using interface implementation, just implement the interface the usual way, so don't include the class(class C in following example) that polymorphs its concrete base class(simulated concrete base class ISecondConcreteClass) in T4:


public partial class C 
{
 ISecondConcreteClass SC { get; set; }
 
 public void World() // think of this as an overriding function? Well it is
 { 
  SC.World();  // think of SC.World() as base.World();

  System.Console.WriteLine ("Long Live!");
 }
 public string Yo() { return SC.Yo(); }
}

Or better yet, copy-paste existing class stub to new partial class file, then delete string "C" from T4's iterated string array, T4 will automatically re-generate A and B class, and shall not generate C class. Then customize your overrides in that partial C class file.


If you want the World method to be overridable further down the inheritance chain, just add the virtual keyword to the method signature:


public partial class C 
{
 ISecondConcreteClass SC { get; set; }
 
 // virtual will make the World overridable down the inheritance chain
 public virtual void World() 
 { 
  SC.World();  // think of SC.World() as base.World();

  System.Console.WriteLine ("Long Live!");
 }
 public string Yo() { return SC.Yo(); }
}



That's multiple inheritance for us C# folks!


Happy Computing! ツ

No comments:

Post a Comment