2010-02-15 3 views
0

J'essaie de décomposer le problème en une description plus simple. J'utilise une bibliothèque de classes externe, qui expose 4 classes de base, toutes très similaires, parfois dérivées les unes des autres.C#: Types de variables dans le délégué

Pendant l'exécution, je suis rappelé sur plusieurs fonctions déléguées, toutes portant un "expéditeur d'objet", qui contient l'objet initial de l'une des 4 classes de base, appelée auparavant sur une fonction API.

échantillon (plus ou moins pseudo-code):

classA oA = new classA(); 
oA.API(callbackA); 

Plus tard, le rappel est appelée, portant oA comme "expéditeur".

void callbackA(object Sender) { 
    classA oA = (classA)Sender; 
    oA.API2(xxx); 
.... 
} 

L'approche ci-dessus fonctionne correctement. Maintenant, je voulais l'étendre aux 3 classes restantes. Parce que la gestion de leurs rappels est plutôt identique, je ne voulais pas répliquer le code encore 3 fois, mais je préférerais que callbackA soit prêt à traiter les Senders de type classB, classC et classD.

Je ne peux pas réaliser ceci dans n'importe quelle solution utile. Quelqu'un peut-il m'aider? MISE À JOUR: Parce que j'ai eu beaucoup de réponse pointant vers "est" - "est" n'est pas une solution. Je dois avoir UNE variable, capable d'avoir plusieurs types. Casting dynamique?

+0

Est-ce que ces classes ont une interface commune? –

+0

Au moins, ils prétendent que B est un descendant de A ... – neil

Répondre

0

Vous pouvez jeter un oeil à is operator C#

L'opérateur est est utilisé pour vérifier si le type d'un objet d'exécution est compatible avec un type donné.

De plus, si ces classes partageaient une interface commune qui vous serait très utile.

+0

Commentaire voir ci-dessus. Bien sûr, je sais à propos de "est", mais cela ne me donne pas une variable pour tous les types. – neil

1

Quelque chose comme:

void callbackA(object Sender) 
{ 
    if (sender is ClassA) 
    { 
    classA oA = (classA)Sender; 
    oA.API2(xxx); 
    } 
    else if (sender is ClassB) 
    { 
    classB oB = (classB)Sender; 
    oB.API2(xxx); 
    } 

    .... 
} 

Il devient beaucoup plus productif lorsque vous pouvez utiliser un baseclass commun ou interface A et B.

+0

Si ce serait si facile ... Comme je l'ai dit: je ne veux pas répéter d'écrire le même code encore et encore. Avec votre approche, j'obtiendrai n variables de types différents. J'ai besoin d'une variable, capable de gérer plusieurs types. – neil

+1

@neil: pour cela vous avez besoin d'un baseclass/interface commun –

1

Je suppose que vous n'utilisez pas une interface commune car la bibliothèque de classes est 'externe' et vous ne pouvez pas accéder à la source. Je suppose également que tous les types concrets possibles pour l'expéditeur exposent le même ensemble de propriétés et de méthodes - en ce qui concerne votre méthode de rappel.

Sans une base ou une interface commune, vous ne pourrez pas éviter la réflexion ou une distribution conditionnelle et un code répété. Vous pouvez cependant encapsuler ce code dans une classe wrapper. Cela améliorerait la lisibilité de votre méthode de rappel.

void callbackA(object sender) 
{ 
    var wrappedSender = new MyWrapper(sender); 
    wrappedSender.API2(); 
} 

Encore une fois, en supposant que toutes les classes de l'expéditeur sont traitées de la même par votre rappel, vous pouvez utiliser System.Reflection dans votre classe wrapper pour appeler la méthode appropriée (ou accéder aux propriétés appropriées). En utilisant API2 comme exemple:

public class MyWrapper 
{ 
    object _wrappedClass; 
    public MyWrapper(object obj) 
    { 
     _wrappedClass = obj; 
    } 
    //... 
    public void API2() 
    { 
     MethodInfo api2 = _wrappedClass.GetType().GetMethod("API2"); 
     api2.Invoke(_wrappedClass); 
    } 
    //... 
} 

Cela ne résout pas votre problème exactement, mais il ne se sépare la réflexion « plomberie » du comportement prévu de votre rappel.

0

L'utilisation de la réflexion pour ce style est incorrecte, vous devez essayer de créer une interface commune pour ces classes et la transmettre au délégué. Si cela est impossible alors envelopper les classes dans des emballages qui partagent une interface, i.e. .:

interface IMyDelegate { 
    public void HandleCallback(); 
} 


class WrapperA : IMyDelegate { 
    private ClassA classA; 
    public WrapperA(ClassA classA) {this.classA = classA;} 
    public void HandleCallback() 
    { 
    /* ... your callback code here ... */ 
    } 
} 

Même pour ClassB, ClassC et ClassD.

Ensuite, vous passez à la Callback et de le jeter à l'interface:

void callback(object sender) { 
    IMyDelegate caller = (IMyDelegate)sender; 
    caller.HandleCallback(); 
} 
+0

Hmm. Merci pour l'indice, qui semble ne pas répondre à mes demandes. Pour illustrer ce dont j'ai besoin, voici un exemple de code et ma solution actuelle: http://maps.alphadex.de/eldos/comment1.txt – neil

Questions connexes