2

What is the best way to implement polymorphic behavior in classes that I can't modify? I currently have some code like:

if(obj is ClassA) {
    // ...
} else if(obj is ClassB) {
    // ...
} else if ...

The obvious answer is to add a virtual method to the base class, but unfortunately the code is in a different assembly and I can't modify it. Is there a better way to handle this than the ugly and slow code above?

zildjohn01
  • 11,339
  • 6
  • 52
  • 58
  • If you have only a couple of if statements, then refactoring might be an overkill. You don't sometimes have to be Patterns-Happy ;) – dance2die Mar 25 '09 at 22:45

5 Answers5

9

Hmmm... seems more suited to Adapter.

public interface ITheInterfaceYouNeed
{
    void DoWhatYouWant();
}

public class MyA : ITheInterfaceYouNeed
{
    protected ClassA _actualA;

    public MyA( ClassA actualA )
    {
        _actualA = actualA;
    }

    public void DoWhatYouWant()
    {
        _actualA.DoWhatADoes();
    }
}

public class MyB : ITheInterfaceYouNeed
{
    protected ClassB _actualB;

    public MyB( ClassB actualB )
    {
        _actualB = actualB;
    }

    public void DoWhatYouWant()
    {
        _actualB.DoWhatBDoes();
    }
}

Seems like a lot of code, but it will make the client code a lot closer to what you want. Plus it'll give you a chance to think about what interface you're actually using.

harpo
  • 41,820
  • 13
  • 96
  • 131
5

Check out the Visitor pattern. This lets you come close to adding virtual methods to a class without changing the class. You need to use an extension method with a dynamic cast if the base class you're working with doesn't have a Visit method. Here's some sample code:

public class Main
{
    public static void Example()
    {
        Base a = new GirlChild();
        var v = new Visitor();
        a.Visit(v);
    }
}

static class Ext
{
    public static void Visit(this object b, Visitor v)
    {
        ((dynamic)v).Visit((dynamic)b);
    }
}

public class Visitor
{
    public void Visit(Base b)
    {
        throw new NotImplementedException();
    }

    public void Visit(BoyChild b)
    {
        Console.WriteLine("It's a boy!");
    }

    public void Visit(GirlChild g)
    {
        Console.WriteLine("It's a girl!");            
    }
}
//Below this line are the classes you don't have to change.
public class Base
{
}

public class BoyChild : Base
{
}

public class GirlChild : Base
{
}
Community
  • 1
  • 1
RossFabricant
  • 12,364
  • 3
  • 41
  • 50
  • 1
    After reading up on wikipedia, it looks like I would need to add a callback method to each class, but I can't modify the classes. Am I reading it wrong? – zildjohn01 Mar 25 '09 at 21:33
  • This does not give dynamic dispatch. Do you actually understand how the Visitor pattern works? – jwg Oct 07 '13 at 10:58
0

I would say that the standard approach here is to wrap the class you want to "inherit" as a protected instance variable and then emulate all the non-private members (method/properties/events/etc.) of the wrapped class in your container class. You can then mark this class and its appropiate members as virtual so that you can use standard polymorphism features with it.

Here's an example of what I mean. ClosedClass is the class contained in the assembly whose code to which you have no access.

public virtual class WrapperClass : IClosedClassInterface1, IClosedClassInterface2
{
    protected ClosedClass object;

    public ClosedClass()
    {
        object = new ClosedClass();
    }

    public void Method1()
    {
        object.Method1();
    }

    public void Method2()
    {
        object.Method2();
    }
}

If whatever assembly you are referencing were designed well, then all the types/members that you might ever want to access would be marked appropiately (abstract, virtual, sealed), but indeed this is unfortunately not the case (sometimes you can even experienced this issue with the Base Class Library). In my opinion, the wrapper class is the way to go here. It does have its benefits (even when the class from which you want to derive is inheritable), namely removing/changing the modifier of methods you don't want the user of your class to have access to. The ReadOnlyCollection<T> in the BCL is a pretty good example of this.

Noldorin
  • 144,213
  • 56
  • 264
  • 302
0

Take a look at the Decorator pattern. Noldorin actually explained it without giving the name of the pattern.

Decorator is the way of extending behavior without inheriting. The only thing I would change in Noldorin's code is the fact that the constructor should receive an instance of the object you are decorating.

Rezlaj
  • 244
  • 1
  • 3
-1

Extension methods provide an easy way to add additional method signatures to existing classes. This requires the 3.5 framework.

Create a static utility class and add something like this:

public static void DoSomething(this ClassA obj, int param1, string param2)
{
    //do something
}

Add a reference to the utility class on the page, and this method will appear as a member of ClassA. You can overload existing methods or create new ones this way.

Adam Lassek
  • 35,156
  • 14
  • 91
  • 107
  • I like it. Unfortunately I'm stuck on .NET 2.0. But here's your upvote anyway – zildjohn01 Mar 25 '09 at 21:38
  • 1
    I think you missed the point -- extension methods can't be virtual. – Jeffrey Hantin Mar 25 '09 at 22:07
  • Virtual methods weren't the point--polymorphic behavior was, and there are different ways of achieving that. Obviously a derived class with virtual methods would be the 'correct' way, but extension methods would be a quick and dirty alternative depending on what you need to accomplish. – Adam Lassek Mar 26 '09 at 13:41
  • 3
    Yes polymorphic behaviour is the point, extension methods won't help achieve that. Overloads will not give you the dynamic dispatch required for polymorphism – Simon Fox Jun 28 '09 at 23:34