0

J'ai un CustomersModule.cs avec la méthode initialize() suivant:Quelqu'un peut-il expliquer la magie qui se passe dans la méthode de résolution de Prism?

public void Initialize() 
{ 
    container.RegisterType<ICustomersRepository, CustomersRepository>(new ContainerControlledLifetimeManager()); 
    CustomersPresenter customersPresenter = this.container.Resolve<CustomersPresenter>(); 

} 

La classe I résoudre du récipient ressemble à ceci:

class CustomersPresenter 
{ 
    private CustomersView view; 
    private ICustomersRepository customersRespository; 

    public CustomersPresenter(CustomersView view, 
     ICustomersRepository customersRepository, 
     TestWhatever testWhatever) 
    { 
     this.view = view; 
     this.customersRespository = customersRepository; 
    } 
} 

Le TestWhatever classe est juste un classe factice J'ai créé:

public class TestWhatever 
{ 
    public string Title { get; set; } 

    public TestWhatever() 
    { 
     Title = "this is the title"; 
    } 

} 

Pourtant, le conteneur résout heureusementCustomersPresenter même si je ne enregistré il, et aussi le conteneur trouve en quelque sorte TestWhatever, instancie, et l'injecte dans CustomersPresenter.

J'ai été assez surpris de réaliser ce puisque je ne trouvais nulle part dans la documentation de Prism qui indiquait explicitement que le conteneur était si automatique.

Donc c'est génial, mais qu'est-ce que le conteneur fait d'autre que je ne sais pas à propos de quoi d'autre peut-il faire que je ne connais pas? Par exemple, est-ce que je peux injecter des classes à partir d'autres modules et si les modules sont chargés, le conteneur les injectera, et sinon, il injectera une valeur null?

Répondre

3

Rien de magique ne se passe. Vous spécifiez des types concrets, donc naturellement ils sont résolvables, car si nous avons l'objet Type, nous pouvons appeler un constructeur dessus.

class Fred { }; 

Fred f1 = new Fred(); 

Type t = typeof(Fred); 

Fred f2 = (Fred)t.GetConstructor(Type.EmptyTypes).Invoke(null); 

La dernière ligne ci-dessus est effectivement ce qui se passe, le type t ayant été trouvé en utilisant typeof sur le paramètre de type que vous donnez à Resolve.

Si le type ne peut pas être construit par new (car il se trouve dans une base de code séparée inconnue), vous ne pourrez pas le donner en tant que paramètre de type à Resolve. Dans le second cas, il s'agit d'une injection constructeur, mais il s'agit toujours d'un type constructible concret connu. Par réflexion, le framework Unity peut obtenir un tableau de tous les types de paramètres pour le constructeur. Le type TestWhatever est constructible, donc il n'y a pas d'ambiguïté ou de difficulté sur ce qu'il faut construire. En ce qui concerne les modules séparés (assemblages), si vous déplacez TestWhatever vers un autre assemblage, cela ne changera pas les lignes de code que vous avez écrites; Cela signifie simplement que vous devez ajouter une référence à l'autre assembly pour que celui-ci soit construit. Et puis TestWhatever est toujours un type constructible référencé sans ambiguïté, donc il peut être construit par Unity. En d'autres termes, si vous pouvez vous référer au type dans le code, vous pouvez obtenir un objet Type, et ainsi, lors de l'exécution, il sera directement constructible.

Réponse au commentaire:

Si vous supprimez la classe TestWhatever, vous obtiendrez une erreur de compilation, parce que vous faites référence à ce type dans votre code. Il ne sera donc pas possible d'obtenir une exécution en faisant cela. Le découplage est toujours en vigueur dans cet arrangement, car vous pouvez enregistrer une instance spécifique de TestWhatever, donc chaque appel à Resolve<TestWhatever>() obtiendra la même instance, plutôt que d'en construire une nouvelle.

+0

Mais d'où vient le découplage, c'est-à-dire si j'ai besoin d'une classe "MenuManager" d'un autre module, et que ce module n'a pas été chargé, je comprends que le conteneur devrait, par exemple. injecter une valeur nulle pour que l'application puisse fonctionner avec ou sans autres parties, mais si par ex. supprimer la classe "TestWhatever" l'application obtenir une erreur. –

+0

Pensez-y: comment allez-vous spécifier que MenuManager doit être créé? –

+0

Avant que le CLR n'exécute une expression comme 'Resolve ();' il doit charger l'assembly contenant la définition de MenuManager. Si vous faites référence à un type dans votre code, vous forcez le chargement de l'assembly contenant cette définition de type. –

2

La raison pour laquelle cela fonctionne parce que Unity est conçu pour cela. Lorsque vous résolvez avec un type concret, Unity cherche à voir s'il peut résoudre à partir du conteneur. Si ce n'est pas le cas, alors ça va juste et instancie le type résolvant ses dépendances. C'est vraiment très simple.

Questions connexes