"Work around" the one base-class limit  
Author Message
Sven De Bont





PostPosted: Common Language Runtime, "Work around" the one base-class limit Top

Hi all,

I would like to add some extra functionality to several existing classes. The implementation of this extra functionality is exactly the same for all the classes.

Unlike some other OO languages (like c++), the .NET framework only allows one baseclass to be used, so I cannot put this implementation in a single class, and derrive my new class from the both the original class AND the class with my extra implementation.

One way to work around this, is to add one property to each of the derrived classes which contains an instance of a class with my new implmentation. But, I would rather extend my classes directly with the new properties and methods.

Is there any way I can accomplish this without have to resolve to copy-paste the implentation in all my derrived classes (and Do I really have no other choice than to copy/paste the implementation in all my derrived classes

Any thoughts




.NET Development34  
 
 
TaylorMichaelL





PostPosted: Common Language Runtime, "Work around" the one base-class limit Top

Extending functionality is normally done through interfaces. Therefore you'd add a new interface to each of your classes to identify the new members. Now the only issue you have is to actually implement them.

A common approach is aggregation. In this situation you'll create a base class that implements the interface. Each of your classes that you want to extend then stores an instance of this class internally. The classes use this instance to expose the interface functionality. It can get tedious as more interfaces are added but you can always create base classes that wrap more and more functionality. If you want your public classes to be able to extend this base class then you can because they already have to expose the interface members so they can react however they want.

interface IFoo
{
void Foo;
}

public class FooBase
{
public virtual void Foo ( ) { }
}

public abstract class BaseClass
{
...
}

public class MyClass1 : BaseClass, IFoo
{
private IFoo m_Foo = new MyClass1Foo();

public void Foo ( )
{ m_Foo.Foo(); }

private class MyClass1Foo ( )
{
public override void Foo ( ) { }
}
}

public class MyClass2 : BaseClass
{
private IFoo m_Foo = new FooBase();
public void Foo ( )
{ m_Foo.Foo(); }
}

In the above example MyClass1 and MyClass2 derive from some base class called BaseClass. I later want to add some functionality Foo so I create a new interface and base class (in this case I make it concrete although it could be abstract). MyClass1 and MyClass2 both implement the interface. MyClass2 uses FooBase to provide the default functionality. MyClass1 however creates a nested class (or perhaps an internal class, it doesn't matter) to change the functionality.

An alternative is to modify the base class (of the classes you want to modify) to implement the interface. Then you can override the implementation in derived classes as though it was their own.

interface IFoo
{
void Foo;
}

public abstract class BaseClass : IFoo
{
public virtual void Foo ( );
}

public class MyClass1 : BaseClass
{
public override void Foo ( ) { }
}

public class MyClass2 : BaseClass
{
public override void Foo ( ) { }
}

Here since I had control over the base class and I wanted all my classes to support the new functionality then I simply modified the base class. Alternatively if I only wanted some classes to implement the functionality then I could create an intermediary base class like so.

interface IFoo
{
void Foo;
}

public abstract class BaseClass
{
...
}

public abstract class FooBaseClass : BaseClass, IFoo
{
public virtual void Foo ( );
}

public class MyClass1 : BaseClass
{
//No foo functionality
}

public class MyClass2 : FooBaseClass
{
public override void Foo ( ) { }
}

Michael Taylor - 10/9/06


 
 
Sven De Bont





PostPosted: Common Language Runtime, "Work around" the one base-class limit Top

Hi Michael,

First of all, thanks for the reply.

In my situation, I don't have access to the base classes. And also, not all classes derrive from the same baseclass. The approach in your first example is from an OO point of view better mine, but still leaves me with that one issue that I won't have access to any of the protected members of the derrived class from within the 'FooBase' class. Or do I

Regards,



 
 
TaylorMichaelL





PostPosted: Common Language Runtime, "Work around" the one base-class limit Top

You have access to the protected members in derived classes from the base class.

Given what I understand about your situation I would say you have this scenario:

Derived1 derives from Base1
Derived2 derives from Base2

You want to add some functionality to both Derived1 and Derived2. You have control over Derived1 and Derived2 (or you can create new derived classes that inherit from them).

Given the above situation you would have no choice but to define the interface and attach it to each derived class. You could create a custom class that implements the core functionalty. If there is functionality that must be implemented in each derived class you can either overload the behavior in the interface implementation in the derived class or make the custom class abstract and create a nested class in each derived class that handled the implementation issues. Nested classes have access to their parent class'es data.

Does this answer your question If not could you provide a more concrete example of what you are trying to do

Michael Taylor - 10/9/06


 
 
Sven De Bont





PostPosted: Common Language Runtime, "Work around" the one base-class limit Top

Nested classes have access to their parent class'es data.

You would think I would know that . This is a good to know thing and I will sure look into that. However, if I'm not mistaken, this still would force me to write the implemantion of the code in each of the internal classes (or at least implement so kind of access to the protected members for the base class).

Thanks again for taking the time (and patience) to help me out.

I made a little example to clarify the track I've been following so far. The classes 'Item' and 'Thing' are 2 existing classes over which I don't have control.

class Item {

private string _color;

public string Color {

get { return _color; }

set { _color = value; }

}

private string _name;

public string Name {

get { return _name; }

set { _name = value; }

}

protected void SomeMethod(){

//do stuff here

}

}

class Thing {

private string _color;

public string Color {

get { return _color; }

set { _color = value; }

}

private string _name;

public string Name {

get { return _name; }

set { _name = value; }

}

protected void SomeMethod(){

//do stuff here

}

}

Now I would like to add an extra property to these classes that is called FullName and return the string concatenation of the Color and Name properties. This is what I got at first:

interface IExtension {

string FullName{get;}

}

class ItemEx : Item, IExtension {

public string FullName {

get { return base.Color + " " + base.Name; }

}

}

class ThingEx : Thing, IExtension {

public string FullName {

get { return base.Color + " " + base.Name; }

}

}

In both derrived classes, the implementation of the FullName property is the same and the code is duplicated. When I use nested classes, I still have to write the implementation of the FullName property in both classes (in a real world situation, the implemtation of the FullName property would be of course very complex and contain 1000's of lines of code).

My next attempt, looked something like this (the interface IExtension is the same as above):

class ExtentionBase : IExtension {

private object _parent;

public ExtentionBase(object parent) {

_parent = parent;

}

public string FullName {

get {

if (_parent is Item)

return ((Item)_parent).Color + " " + ((Item)_parent).Name;

else if (_parent is Thing)

return ((Thing)_parent).Color + " " + ((Thing)_parent).Name;

else

return null;

}

}

}

class ItemEx2 : Item, IExtension {

private IExtension _myExt;

public ItemEx2() : base()

{

_myExt = new ExtentionBase(this);

}

public string FullName {

get { return _myExt.FullName; }

}

}

class ThingEx2 : Item, IExtension {

private IExtension _myExt;

public ThingEx2()

: base() {

_myExt = new ExtentionBase(this);

}

public string FullName {

get { return _myExt.FullName; }

}

}

The implementation of the FullName property is now contained in the class ExtensionBase and does not need duplicating. There's still a lot work to be done by 'wrapping' each member of the IExtention interface in each of the classes, but I could live with that. That is, until I realized that I couldn't access the protected members of the Item or Thing class from within the ExtentionBase class (duh).

There probably isn't 'one' solution for this, but I'm looking for the best approach.

Regards



 
 
TaylorMichaelL





PostPosted: Common Language Runtime, "Work around" the one base-class limit Top

Since Item and Thing do not share anything in common there really is no way to create one set of code to interact with both of them. I don't really see that multiple inheritance would have helped you either because no matter how you slice it they are separate classes so the only thing you could have really done was create a new class that derived from Item and Thing. However this is IMHO a misuse of inheritance because this hybrid object is using inheritance strictly to gain access to protected members rather than be a specialization of either of the classes.

Basically however all you are really trying to do is add additional functionality to the classes. Therefore you need to force both classes to inherit from the same base or implement the same interface. Given the goal of reducing the amount of code you have to write you can create an intermediary interface consumed by your IExtension interface and implemented by Item and Thing-derived classes. Due to C#'s implicit interface implementation all public members will automatically work so you don't have to do anything. For each protected member however you'll have to expose a new method on the interface and implement it in the derived class. You should be careful exposing protected members though as they are often not designed for use outside the class itself.

class Item { /*Unchanged */ }
class Thing { /* Unchanged */ }

interface IItemThing
{
//Each public member from Item/Thing that you want exposed
string Color { get; set; }
string Name { get; set; }

//Protected members will have to be renamed
void SomeWork ( );
}

//New derived class
class ItemEx : Item, IItemThing
{
//Only members added to expose protected members need be defined here
public void SomeWork ( )
{
SomeMethod();
}
}

class ThingEx : Thing, IItemThing
{
public void SomeWork ( )
{
SomeMethod();
}
}

//The interface you want to work with (or it could be a class, doesn't matter)
interface
IExtension
{
string FullName { get; }
}

class ExtensionBase : IExtension
{
//This is the key, now that both Item and Thing implement a common interface/base class we
//can treat them the same
private IItemThing m_Item;
public ExtensionBase ( IItemThing item )
{ m_Item = item; }

//One implementation for each new piece of functionality
public string FullName
{
get { return m_Item.Color + " " + m_Item.Name;
}
}

You can use a generic class if you want as well but I went with a constructor parameter here. Once both classes map to a common type you can treat them the way you want. You still have to force everyone to create instances of your ItemEx or ThingEx class though.

As a final warning I would recommend that you step back and make sure that this solution is really what you want. It is sort of convoluted just to work around an implementation (inheritance) detail. Ultimately it would be best if you could rearchitect the system to force Item and Thing to derive from some base class which would then resolve all your problems. Alas I understand sometimes politics and/or circumstances prevent it but I'd definitely mark this code as needing a design review if the opportunity ever arises to change the implementation.

Michael Taylor - 10/10/06


 
 
Sven De Bont





PostPosted: Common Language Runtime, "Work around" the one base-class limit Top

I don't really see that multiple inheritance would have helped you either because no matter how you slice it they are separate classes so the only thing you could have really done was create a new class that derived from Item and Thing.

I realized that when I was producing the example in my last post. It's just something I remembered from a C course that I took last century.

So the bottem line is: I'm trying to do something I'm not suppose to do

It's like you say (and I quote):

    • However this is IMHO a misuse of inheritance...
    • You should be careful exposing protected members though...
    • You still have to force everyone ...

In the end, the procuded code would be hard to understand and probably still dificult to maintain.

I will most likely revert to duplicating the code in each derrived class. With the partial class feature in VS 2005, I can add a custom action to the build process to make sure the implementation is the same for all classes.

Thanks for your help.

Regards,