Domanda

Supponiamo di avere classi legacy, che non possono essere modificate:

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

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

Voglio scrivere un aiutante con tale firma:

void Calc(object obj, int a);

Si noti che il primo argomento è di tipo 'oggetto'. Il codice del test dovrebbe essere un po 'come questo:

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

La domanda è: quale implementazione puoi immaginare oltre a queste:

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

Grazie!

È stato utile?

Soluzione

Vorrei andare per l'esempio 1, perché è il più semplice e il più ovvio.

Userei l'esempio 2 solo se ti aspetti nuovi tipi di oggetti con uno di questi due metodi, e l'esempio 3 solo se hai molti (decine se non centinaia) di oggetti e le prestazioni iniziano a essere un problema.

Modifica: o metodi di estensione se sei .Net 3

Altri suggerimenti

Utilizza i metodi di estensione per aggiungere essenzialmente una nuova funzione a un tipo esistente.

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

Ecco come scriverei la soluzione. Riduce il rischio di problemi di sicurezza del tipo nel codice ed elimina la riflessione.

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

puoi sempre utilizzare modello di adattatore per implementare gli oggetti legacy immutabili, senza rompere qualsiasi oggetto dipendente dalla sua funzionalità, pur essendo in grado di implementare la propria (nuova) funzionalità sull'oggetto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top