J'ai vu des exemples de ceci où une interface est fournie à une usine et elle génère des objets qui implémentent l'interface. Ce n'est pas si compliqué pour moi, mais ce que je ne comprends pas c'est comment cela peut être utilisé pour implémenter un comportement. Prenez par exemple la ChannelFactory dans WCF ... lorsque vous générez un canal à partir d'une interface, il expose des méthodes (de l'interface) qui, lorsqu'elles sont appelées, appellent des procédures distantes. Je semble avoir un petit écart dans mes connaissances sur la façon dont cela peut être fait. C'est probablement un modèle de conception commun, mais j'ai pensé que j'utiliserais SO comme une extension de recherche une fois de plus.Comment une classe peut-elle être conçue pour simuler un type inconnu?
Répondre
Généralement, cela se produit par l'émission de code. Voir les classes dans System.Reflection.Emit. Par exemple, vous pouvez obtenir une interface Type et passer en revue les méthodes déclarées, puis créer votre propre type qui l'hérite, en utilisant TypeBuilder, et implémenter toutes les fonctionnalités que vous désirez dans les méthodes (ou juste les rendre vides/faire un retour par défaut (T)), en utilisant MethodBuilder, et ainsi de suite, jusqu'à ce que vous ayez satisfait l'interface.
Les cadres de simulation qui simulent une interface génèrent une classe dynamique qui implémente l'interface. Le comportement de la (des) méthode (s) simulée (s) dépendra du framework. Généralement, la méthode ne fera rien à moins qu'une implémentation soit fournie à travers le simulacre.
Par exemple:
Mock<IRepository> repMock = new Mock<IRepository>();
repMock.Setup(r => r.FindById(1)).Returns(new MyObject());
En supposant que l'interface définit une méthode IRepository
FindByID
, le procédé Setup
de la maquette génère dynamiquement une mise en oeuvre du procédé et « injecte » dans la maquette. Ceci est fait en utilisant Reflection.Emit
, qui peut être utilisé pour construire dynamiquement des instructions IL et les compiler à la volée.
Le repMock ne serait-il pas simplement de type IRepository? Un objet fortement typé "Mock" ne serait pas considéré comme un IRepository lui-même. Au-delà de cela, oui, le framework utilisera généralement la réflexion pour générer dynamiquement certaines variations d'une classe MockBase qui implémente l'interface désirée, et les méthodes exposées par l'interface sont implémentées en utilisant des callbacks aux membres MockBase centralisés qui contrôlent le comportement attendu. –
KeithS
@Keith: repMock est de type Moq.Mock. Le repMock.Object est une classe générée dynamiquement qui implémente IRepository. Le programme d'installation injecte une implémentation dans la classe pour toutes les méthodes définies par l'interface. –
OK, je suis habitué à RhinoMocks, où vous utilisez des méthodes statiques GenerateMock pour produire une classe qui ressemble à un IRepository. Moq est apparemment un peu différent. – KeithS