2009-09-30 10 views
1

J'ai une méthode protégée dans une classe de base qui accepte un Func <T> puis se retourne et s'exécute avec un bien supplémentaire. Exemple d'utilisation:Appel de méthode de redirection dans le délégué

public MyResponse DoSomething(MyRequest request) 
{ 
    return base.Execute(() => this.Channel.DoSomething(request)); 
} 

Ce que je cherche à faire est de prendre l'instance func délégué et rediriger l'appel de méthode dans l'expression à une autre instance en plus this.Channel, donc quelque chose comme:

protected TResponse Execute<TResponse>(Func<TResponse> command) 
{ 
    return command.Method.Invoke(this.otherInstanceOfChannel, command.Target); 
} 

Ici le "this.otherInstanceOfChannel" serait une instance d'une classe concrète différente de celle "this.channel" passée dans l'appel original mais implémente la même interface. J'ai juste besoin de comprendre quelle méthode est appelée et l'exécuter sur une autre instance en passant les arguments d'origine de l'appelant. J'ai commencé le chemin de MethodCallExpressions et similaires mais mon expression-foo est faible ...

Édité/réécrit pour plus de clarté - espérons que cette version a plus de sens.

Merci, Matt

+0

Est-il impossible d'accepter l'instance en tant que paramètre? Cela impliquerait beaucoup moins de supercherie ... – bobbymcr

+0

Bien sûr, mais en essayant de voir s'il est possible de faire ce que je veux sans casser beaucoup de code qui appelle ça ... beaucoup de code que je ne contrôle pas, malheureusement ... – matt

+0

Voulez-vous dire que 'Execute' est une méthode que vous implémentez? C'est à dire. vous pouvez changer sa signature et sa mise en œuvre? –

Répondre

1

Oui, vous pouvez le faire. Pas le temps en ce moment pour vous donner la solution complète, mais voici un squelette de ce que vous feriez:

protected TResponse Execute<TResponse>(Expression<Func<TResponse>> command) 
{ 
    // Check that the expression is in the correct format (ie you are calling a method off of a type Channel 
    // Get the name of the method call. Something like: 
     var node = expr.Body as MemberExpression; 
     if (object.ReferenceEquals(null, node)) 
      throw new InvalidOperationException("Expression must be of member access"); 
     var methodName = node.Member.Name; 
    // Use reflection to invoke methodName on otherInstanceOfChannel 
    // Cast the results to TResponse and return 
} 

Comme vous pouvez le voir le seul vrai truc est l'utilisation de l'expression <>. Le changement de type est transparent pour tout code client - ils n'ont pas besoin de changer du tout. Here is some code pour commencer à analyser les arbres d'expression.

+0

J'ai fini par découvrir une autre façon de le faire sans expression monkeying, mais votre méthode a travaillé pour la façon dont j'essayais de le faire - merci - se souviendra de cela pour l'avenir. – matt

1

Je crois que vous pouvez fournir l'exemple dans l'expression lambda comme ceci:

IMyChannel myChannelInstance = MyChannelInstanceFactory.Create(); 
Execute(() => myChannelInstance.DoSomething(request)) 

Si cela ne peut être fait avec des expressions lambda et je suis sûr qu'ils peuvent vous peut changer cela à un délégué et cela fonctionnerait bien. L'expression lambda pointe vers un bloc d'exécution de code et, en tant que tel, vous pouvez mettre tout ce qui correspond aux arguments d'expression dans ce bloc de code.

+0

Désolé - n'était probablement pas clair avec ma question - voir ma réponse à Pavel ci-dessus ... – matt

+0

Eh bien, vous pouvez simplifier cela en rendant la méthode de classe de base virtuelle et remplacer celle de la classe dérivée. La méthode de classe de base invoquerait sur l'instance normale et la classe de dérivation pourrait remplacer ce comportement dans sa propre instance –

+0

Certainement - si je ne peux pas faire fonctionner ce travail dans la seule implémentation de la méthode Execute, alors je chercherai des façons de changer la signature de la méthode pour répondre à mes besoins et forcer tout le monde à changer leur code - essayait d'éviter cela si je le pouvais. – matt

Questions connexes