Comment utiliser Unity avec des classes internes?

J’ai une application Web API et j’utilise Unity pour l’dependency injections. L’application utilise une bibliothèque contenant un Interface IDoStuff et une classe qui implémente l’interface:

internal interface IDoStuff { void DoSomething(); } internal class DoStuff : IDoStuff { public void DoSomething() { // Do some stuff } } 

La bibliothèque a également une classe publique qui doit faire des choses:

 public class NeedToDoStuff { private IDoStuff doStuff; public NeedToDoStuff() { this.doStuff = new DoStuff(); } internal NeedToDoStuff(IDoStuff doStuff) { this.doStuff = doStuff; } void PleaseDoStuff() { doStuff.DoSomething(); } } 

J’aimerais utiliser Unity pour créer une instance de NeedToDoStuff dans mon contrôleur et être également responsable de la création de la classe DoStuff en interne, plutôt que du constructeur appelant directement new. Cependant, la seule façon de procéder consiste à rendre publiques l’interface de IDoStuff et la classe DoStuff, ce qui me semble erroné. Cela semble faux car ce sont des détails d’implémentation et ne sont pertinents que dans la bibliothèque elle-même. Je comprends qu’en inversion de contrôle, vous permettez à l’application de niveau supérieur de faire des choix concernant ses implémentations sous-jacentes via une configuration quelconque, mais cela devrait-il signifier qu’il n’y a plus besoin de interne, etc.?

Oubliez un instant que vous utilisez un conteneur et supposons que vous créez ces classes vous-même dans le chemin de démarrage de votre application. Comment feriez-vous cela en C #?

La réponse est que vous ne pouvez pas. Cela ne sera tout simplement pas compilé en C #, car C # exige que ces types soient publics. Ainsi, bien que ces types puissent être un détail d’implémentation par rapport à d’autres composants, ils ne sont pas un détail d’implémentation pour la partie de votre application qui les relie ensemble. Que vous utilisiez ou non une bibliothèque DI pour vous aider est sans importance; cette bibliothèque doit avoir access à ces bibliothèques, car ces classes ne sont pas des détails d’implémentation.

Et notez qu’il y a différentes façons de cacher ces classes. Vous pouvez déplacer les interfaces dans leur propre assemblage et laisser la bibliothèque consommasortingce et la bibliothèque contenant les implémentations dépendre de ce nouvel assemblage ‘contrat’. Lorsque vous ne laissez pas l’assembly consommateur dépendre de l’assembly d’implémentation, les types d’implémentation sont effectivement masqués de l’assembly consommateur, même si ces types sont toujours publics.

Si je suis personnellement contre les interfaces internes, vous pouvez autoriser l’unité à les utiliser en ajoutant

 [assembly: InternalsVisibleTo("Unity_ILEmit_InterfaceProxies")] 

au fichier AssemblyInfo.cs du projet contenant vos interfaces. J’ai trouvé cela après avoir tenté d’append [assembly: InternalsVisibleTo (“Microsoft.Practices.Unity”)], ce que je n’ai pas vu fonctionner dans un autre message et n’a eu aucun effet, mais a estimé que c’était la bonne direction. Le stacktrace que j’ai extrait de mon code faisait référence à l’assembly ci-dessus et permettait au code de fonctionner.

Cela vous permettrait de cacher vos interfaces. Le constructeur est une autre histoire cependant.

J’ai posté ma propre réponse, car je pense que cela me rapproche le plus de ma question initiale. Ce n’est peut-être pas un choix de conception aussi épuré que les recommandations de Steven, mais que vous l’aimiez ou le détestiez, cela permet d’utiliser les classes internes d’une bibliothèque avec Unity.

J’avais besoin de faire trois mises à jour des classes / interfaces:

  1. Rendre les interfaces publiques.
  2. Rendre les constructeurs publics.
  3. Introduisez une classe / méthode statique qui effectue un enregistrement d’unité dans la bibliothèque appelée à partir de la logique d’enregistrement d’unité principale effectuée au démarrage de l’application.