2009-03-06 6 views
1

Supposons que nous avons des classes existantes, qui ne peut pas être modifié:C#. Ajouter polymorphisme pour le code existant

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

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

Je veux écrire un assistant avec une telle signature:

void Calc(object obj, int a); 

avis que le premier argument est de type 'objet'. Le code de test doit être un peu comme ceci:

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

La question est, ce que vous pouvez imaginer la mise en œuvre, en plus de ceux-ci:

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

Merci!

+0

Essayez-vous d'obtenir, en substance, un appel de fonction virtuelle? – Qwertie

+0

Non, je n'appelle pas de fonction virtuelle. Mais qu'est-ce que cela changerait? – alex2k8

Répondre

0

Je voudrais aller par exemple 1, parce que c'est le plus simple et le plus évident. Je n'utiliserais l'exemple 2 que si vous attendez de nouveaux types d'objets avec l'une de ces deux méthodes, et l'exemple 3 seulement si vous avez beaucoup (des dizaines sinon des centaines) d'objets et que les performances commencent à poser un problème.

Edit: ou l'extension des méthodes si vous êtes .Net 3

3

Utilisez des méthodes d'extension pour ajouter essentiellement une nouvelle fonction à un type existant.

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

+0

Extension ne devrait pas ajouter le polymorphisme par lui-même. J'ai ajouté Example4, qui utilise l'approche similaire. Le code d'extension devrait être presque le même. – alex2k8

2

Voici comment j'écrire la solution. Il réduit le risque de problèmes de sécurité de type dans le code et élimine la réflexion.

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

vous pouvez toujours utiliser la adapter pattern pour mettre en œuvre les objets anciens invariables, sans casser des objets dépendant de sa fonctionnalité, tout en étant mise en œuvre ableto votre (nouveau) fonctionnalité à l'objet.

Questions connexes