Search code examples
c#polymorphismlegacy-codeduck-typing

C#. Add polymorphism for legacy code


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!


Solution

  • 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