views:

325

answers:

4

Hello,

Assume we have legacy classes, that can't be modified:

class Foo 
{
    public void Calculate(int a) { }
}

class Bar
{
    public void Compute(int a) {}
}

I want to write a helper with such signature:

void Calc(object obj, int a);

Notice, that the first argument is of type 'object'. The test code should be some like this:

ExampleX.Calc((object)new Foo(), 0);
ExampleX.Calc((object)new Bar(), 0);

The question is, what implementation you can imagine in addition to these:

// Using If/then
class Example1
{
    public static void Calc(object obj, int a)
    {
        if (obj is Foo)
            ((Foo)obj).Calculate(a);
        else if (obj is Bar)
            ((Bar)obj).Compute(a);
    }
}

// Using reflection
class Example2
{
    private static Dictionary<Type, MethodInfo> _methods = new Dictionary<Type, MethodInfo>();

    static Example2()
    {
        _methods.Add(typeof(Foo), typeof(Foo).GetMethod("Calculate"));
        _methods.Add(typeof(Bar), typeof(Bar).GetMethod("Compute"));
    }

    public static void Calc(object obj, int a)
    {
        _methods[obj.GetType()].Invoke(obj, new object[] { a });
    }
}

// Using delegates
class Example3
{
    private delegate void CalcDelegate(object obj, int a);

    private static Dictionary<Type, CalcDelegate> _methods = new Dictionary<Type, CalcDelegate>();

    static Example3()
    {
        _methods.Add(typeof(Foo), (o, a) => ((Foo)o).Calculate(a));
        _methods.Add(typeof(Bar), (o, a) => ((Bar)o).Compute(a));
    }

    public static void Calc(object obj, int a)
    {
        _methods[obj.GetType()](obj, a);
    }
}

// Using Reflection + overloaded methods
class Example4
{
    private delegate void CalcDelegate(object obj, int a);

    public static void Calc(object obj, int a)
    {
        Type[] types = new Type[] { 
            obj.GetType(), typeof(int)
        };

        typeof(Example4).GetMethod("Calc", types).Invoke(null, new object[] { obj, a });
    }

    public static void Calc(Foo obj, int a)
    {
        obj.Calculate(a);
    }

    public static void Calc(Bar obj, int a)
    {
        obj.Compute(a);
    }
}

Thanks!

+3  A: 

Use extension methods to essentially add a new function to an existing type.

http://msdn.microsoft.com/en-us/library/bb383977.aspx

Brian Ensink
Extension whould not add polymorphism by itself. I added Example4, that uses the similar approach. Extension code whould be almost the same.
alex2k8
+2  A: 

This is how I would write the solution. It reduces the risk of type safety problems in the code and eliminates reflection.

class Example2
{
    private static Dictionary<Type, Action<object,int>> _methods = new Dictionary<Type, Action<object,int>>();

    static Example2()
    {
        Add<Foo>( (f,a) => f.Calculate(a) );
        Add<Bar>( (b,a) => b.Compute(a) );
    }

    public static void Calc<TSource>(TSource source, int a)
    {
        _methods[typeof(TSource)](source,a);
    }

    public static void Add<TSource>(Action<TSource,int> del) 
    {
        Action<object,int> wrapper = (x,i) => { del((TSource)x, i); }; 
        _methods[typeof(TSource)] = wrapper;
    }
}
JaredPar
A: 

I would go for example 1, because its the simplest one and most obvious.

I would use Example 2 only if you expect new types of objects with one of these two methods, and example 3 only if you have a lot (tens if not hundreds) of objects and performance starts being an issue.

Edit: Or extension methods if you are .Net 3

Grzenio
+1  A: 

you could always use the adapter pattern to implement the unchangeable legacy objects, without breaking any objects dependant on its functionality, while still being ableto implement your own (new) functionality to the object.

SnOrfus