views:

462

answers:

5

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?

+4  A: 

Check out the Visitor pattern. This lets you come close to adding virtual methods to a class without changing the class. You will want to have your Visitor class take a parameter that is a common super class of the objects you want to visit. In your case it sounds like that will be Object, which all classes in C# inherit from.

You can add the Visit method as an LINQ extension method.

RossFabricant
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
+7  A: 

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
Really? How? What's the other interface zildjohn is trying to adapt to...? Visitor fits well.
Pontus Gagge
A: 

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
This is functionally the same as the adapter pattern as noted by harpo.
SnOrfus
Yeah, I realised after he edited his post to include the code sample. Ah well, guess his original post beat me to it...
Noldorin
+1  A: 

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
I like it. Unfortunately I'm stuck on .NET 2.0. But here's your upvote anyway
zildjohn01
I think you missed the point -- extension methods can't be virtual.
Jeffrey Hantin
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
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
A: 

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