Problème
Je suis avec la mise en œuvre des plugins pour une application MEF WinForms et je remarque un comportement avec la composition que je ne comprends pas.MEF - aide pour comprendre ce qui se passe avec le récipient et la composition
Juste pour le sortir du chemin, j'utilise avec .NET 4. MEF
Comme une sorte de tl; dr, voici ce que je ne suis pas clair en ce qui concerne les conteneurs et la composition :
- Si je construis un récipient à l'intérieur d'une classe qui est, elle-même, une partie exportée et appelle
ComposeParts(this)
est l'instance existante de cette catégorie a été ajoutée au conteneur ou est une autre instance créée? - Lorsque j'utilise la méthode
GetExportedValue<T>()
, la pièce retournée doit-elle déjà être composée (ou a-t-elle rempli ses importations) ou dois-je explicitement composer la pièce?
Lire la suite pour plus de détails sur chaque question ...
Contexte
En ce qui concerne la première question, j'ai un formulaire de demande principale qui a un panneau qui application hôte « normale » usercontrols comme ainsi que les contrôles userc des plugins. Ce formulaire d'application principal implémente une interface appelée IHostingForm
qui lui permet d'exposer certaines de ses propres fonctionnalités aux plugins. Ce formulaire d'application principal s'exporte à travers l'interface IHostingForm
et a une importation qui doit être remplie. Voici un extrait de code:
[Export(typeof(IHostingForm))]
public partial class frmMain : RibbonForm, IHostingForm
{
//public/private form methods here...
private CompositionContainer _container;
//An import that needs to be filled.
[ImportMany]
public IEnumerable<Lazy<IAddInController, IAddInControllerMetadata>> AddInControllers;
public frmMain()
{
//Init code here omitted to save space...
//Setup the container
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
//Temporary location while testing...
catalog.Catalogs.Add(new DirectoryCatalog(Application.StartupPath));
_container = new CompositionContainer(catalog);
try
{
//Is the current instance of the class (this) added to the
//container or does the container construct its own instance?
_container.ComposeParts(this);
}
catch (CompositionException ex)
{
//Error catching code omitted...
}
}
//IHostingForm implementation
public void AddTabToTabBar(string tabText)
{
RibbonTab rt = new RibbonTab(tabText);
//Some more init code here which I'm leaving out to save space...
this.ribbonBar1.CommandTabs.Add(rt);
}
//etc...
}
Avis dans l'extrait ci-dessus comment il est lui-même exportateur, mais il appelle également ComposeParts(this)
dans le constructeur? Est-ce que cela crée une instance distincte du formulaire ou est ComposeParts(this)
suffisamment intelligent pour savoir utiliser l'instance déjà existante et l'ajouter simplement au conteneur?
Ceci conduit à ma deuxième question. Comme je ne savais pas si la méthode de composition que j'utilisais était correcte ou non, j'ai essayé de créer le conteneur dans la classe Program de l'application et j'ai trouvé un autre comportement que je ne comprends pas. Je me suis déplacé le code d'initialisation du conteneur de la classe de la forme et dans le Programme comme celui-ci:
static class Program
{
internal static CompositionContainer _container;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Setup the container
var catalog = New AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
catalog.Catalogs.Add(new DirectoryCatalog(Application.StartupPath));
_container = new CompositionContainer(catalog);
IHostingForm frm = _container.GetExportedValue<IHostingForm>();
//If I don't call this, the form's imports don't get satisfied
_container.CompostParts(frm);
Application.Run((Form)frm);
}
}
Sur la base de la documentation sur MSDN et aussi the answer to this question, j'avais l'impression que la méthode GetExportedValue<T>()
instancierez l'exportation des données taper et aussi le composer (ou satisfaire ses dépendances?) parce qu'il sortait du conteneur. Mais grâce à des tests, il semble que, après avoir obtenu la pièce du conteneur, je dois explicitement dire au conteneur de composer la pièce afin de remplir ses importations. Cela semble contredire ce que j'ai lu jusqu'ici.
Je ne savais pas si c'était plusieurs questions ou non. Si elles doivent être divisées, faites le moi savoir et je serai heureux de modifier cette question et d'en créer une autre. Mais, pour moi, ils semblent liés en ce sens qu'ils traitent tous deux de mon manque de compréhension de ce qui se passe avec le conteneur et la composition.