C #. Добавить полиморфизм для старого кода - PullRequest
1 голос
/ 06 марта 2009

Предположим, у нас есть устаревшие классы, которые нельзя изменить:

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

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

Я хочу написать помощника с такой подписью:

void Calc(object obj, int a);

Обратите внимание, что первый аргумент имеет тип 'объект'. Тестовый код должен выглядеть примерно так:

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

Вопрос в том, какую реализацию вы можете представить в дополнение к этим:

// 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);
    }
}

Спасибо!

Ответы [ 4 ]

3 голосов
/ 06 марта 2009

Используйте методы расширения, чтобы по существу добавить новую функцию в существующий тип.

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

2 голосов
/ 06 марта 2009

Вот как бы я написал решение. Это снижает риск проблем с безопасностью типов в коде и исключает возможность отражения.

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;
    }
}
1 голос
/ 06 марта 2009

вы всегда можете использовать шаблон адаптера для реализации неизменяемых устаревших объектов, не нарушая никаких объектов, зависящих от его функциональности, и в то же время сохраняя возможность реализовать свои собственные (новые) функциональные возможности для объекта.

0 голосов
/ 06 марта 2009

Я бы пошел к примеру 1, потому что это самый простой и самый очевидный.

Я бы использовал Пример 2, только если вы ожидаете новые типы объектов одним из этих двух методов, и пример 3, только если у вас много (десятки, если не сотни) объектов, и производительность становится проблемой.

Редактировать: Или методы расширения, если вы .Net 3

...