2010-05-12 2 views
5

J'ai un objet o qui a garanti à l'exécution être l'un des trois types A, B, ou C, qui mettent en œuvre une interface commune I. Je peux contrôler I, mais pas A, B ou C. (Ainsi, je pourrais utiliser une interface de marqueur vide, ou en quelque sorte tirer parti des similitudes dans les types en utilisant l'interface, mais je ne peux pas ajouter de nouvelles méthodes ou modifier les existantes dans les types.)Comment envoyer vers une méthode basée sur le type d'exécution d'un paramètre dans C# <4?

J'ai aussi un série de méthodes MethodA, MethodB et MethodC. Le type d'exécution o est recherché et est ensuite utilisé en tant que paramètre pour ces méthodes.

public void MethodA(A a) { ... } 
public void MethodB(B b) { ... } 
public void MethodC(C c) { ... } 

En utilisant cette stratégie, en ce moment une vérification doit être effectuée sur le type de o pour déterminer quelle méthode devrait être invoquée. Au lieu de cela, je voudrais simplement avoir trois méthodes surchargées:

public void Method(A a) { ... } // these are all overloads of each other 
public void Method(B b) { ... } 
public void Method(C c) { ... } 

Maintenant, je laisse C# faire l'expédition au lieu de le faire moi-même manuellement. Cela peut-il être fait? L'approche simple naïve ne fonctionne pas, bien sûr:

Impossible de résoudre la méthode 'Méthode (objet)'. Les candidats sont les suivants:

  • Procédé vide (A)
  • Procédé vide (B)
  • Procédé vide (C)
+0

l'essayer? la-la-la –

+0

S'il y avait des types D et E et F auraient-ils tous besoin d'une implémentation de la méthode aussi? –

+0

@Jason: Vraisemblablement, oui, mais dans mon cas particulier, d'autres types de ce type sont peu susceptibles d'exister. –

Répondre

5

Que diriez-vous de quelque chose comme ceci?

private Dictionary<Type, Action<I>> _mapping = new Dictionary<Type, Action<I>> 
{ 
    { typeof(A), i => MethodA(i as A)}, 
    { typeof(B), i => MethodB(i as B)}, 
    { typeof(C), i => MethodC(i as C)}, 
}; 

private void ExecuteBasedOnType(object value) 
{ 
    if(_mapping.ContainsKey(value.GetType())) 
     _mapping(value.GetType())(value as I); 
} 
+0

Ha, c'est en fait ce que j'ai actuellement en ce moment! Évidemment, ce n'est pas aussi bon que de laisser C# faire la dépêche d'une manière ou d'une autre. –

+0

Si vous avez le contrôle sur I, A, B et C, vous pouvez ajouter quelque chose à ce que j'appelle ExecuteMethod() et je l'appelle simplement sur I. Sinon, vous devez le mapper en quelque sorte. –

+0

Ceci est votre meilleure option si vous ne pouvez pas appliquer la suggestion de Kobi. Une double répartition/modèle de visiteur ne peut pas être fait, sauf si vous contrôlez les classes non plus. –

0

Si la 3 classes A, B et C implémente l'interface Je ne devrais rien faire. Il est le moteur d'exécution qui choisissent la bonne méthode pour vous:

A a = new A(); 
class.Method(a); // will calll Method(A a) 

B b = new B(); 
class.Method(b); // will call Method(B b) 
+0

Cela ne répond pas à la question correctement (ou du moins ne comprend pas ce que je disais). Je n'ai pas de 'A' ou' B'; J'ai un 'object' (voir la première phrase). –

0

Preseumably O est déclarée en tant que type/interface I instancié soit comme un b ou c. La façon de le faire serait d'avoir une seule méthode publique, la prise d'un paramètre de type I et ensuite faire votre logique au sein de cette méthode, par exemple. Appelez la méthode privée AB ou C.

En lisant votre message édité, o est de type objet, n'oubliez pas d'être clair lorsque vous prenez un objet car il s'agit d'un type générique pour une instance de une classe. Pourquoi le déclarez-vous comme un objet, plutôt que comme un i, pourrait-il être quelque chose d'autre plus tard? Si tel est le cas, pour utiliser vos méthodes surchargées, vous devrez le décocher avant d'appeler la méthode. par exemple.

if (o.GetType() == typeof(a)) 
{ 
    oa = (a)o; 
    Method(oa); 
} 
else if(o.GetType() == typeof(b)) 
{ 
    ... 
} 

Etc.

Alternativement, si vous avez fait la méthode prendre une paramater de type i vous pourriez faire quelque chose comme:

i oi = (i)o; 
Method(oi); 

Mais vous auriez encore besoin de faire quelque chose comme le premier exemple dans votre méthode publique.

7

Si vous pouvez factoriser, déplacez la méthode à l'interface et ont chaque classe a sa mise en œuvre:

I i = o as I; 
i.Method(); 
+0

+1 Exactement ce que j'étais sur le point de dire. –

+0

J'ai édité pour clarifier que je contrôle «I», mais pas «A», «B» ou «C». Mais ce serait génial si je pouvais! –

+0

@Evan, utilisez des classes partielles (voir ma réponse) – tster

0

Je ne suis pas 100% sûr que cela fonctionnera dans votre scénario, mais il semble que vous pourriez être en mesure d'utiliser des classes partielles:

public interface IMethodCallable 
{ 
    public void Method(); 
} 

public partial class A : IMethodCallable 
{ 
    public void Method() 
    { 
     .... 
    } 
} 

puis pour l'utilisation:

object o = getObject(); // we know this is A, B or C 
((IMethodCallable)o).Method(); 
Questions connexes