Today I would like to talk about lazy loading of application parts.
When we use the [Import] or [ImportMany] attributes we are telling MEF to fill our variable with an instance of our desired type. This approach is great if we are dealing with small types, or we are certain that we need this instance, but what if the type we want to import is quite heavy and it would be a waste to load it right on the start? What if we want to import the types based on some user settings or a plug-in system?
The solution for this is using Lazy
Lazy
The Lazy
MEF knows to work with Lazy
If we will continue my previous post, instead of importing this way:
[ImportMany(typeof(IModule))] private List<IModule> _modules;
We would do something like that:
[ImportMany(typeof(IModule))] private List<Lazy<IModule>> _modules;
This way, when the OnImportsSatisfied method is called, our _modules variable will be filled with Lazy
In order for us to instantiate a module we will have to read the Value property like that:
IModule firstModule=_Modules[0].Value; //Only now our imported module will be instantiated. Since we read its Value property
But here comes the question: “How would you know which module to load?”
In order to identify the modules I “lazy imported”, we will have to provide a metadata to each exported type using the [ExportMetadata] attribute.
[Export(typeof(IModule))]
[ExportMetadata("Name", "Gui Designer")]
[ExportMetadata("RequiresAdmin", true)] //Just to demonstrate you can use any type in the metadata
public class GuiDesignerViewModel : IModule
……
Ok, so now that we have some metadata in our exported types we will have to define an interface for it. (its usage will be explained bellow)
public interface IModuleMetadata
{
string Name { get; }
bool RequiresAdmin { get; }
}
And change our lazy import definition to include the metadata.
[ImportMany(typeof(IModule))] private List<Lazy<IModule, IModuleMetadata>> _modules;
That’s it !
MEF will automatically fill our IModuleMetadata with the values we set with ExportMetadata, without instantiating the type itself.
In order for us to check which module we want to load, we can check the lazy metadata.
public void OnImportsSatisfied()
{
foreach (Lazy<IModule, IModuleMetadata> module in _modules)
{
if(module.Metadata.RequiresAdmin==false)
{
Debug.WriteLine("Module loaded: " + module.Metadata.Name);
_loadedModules.Add(module.Value); //Will create an instance
}
}
}
Or we can instantiate it when we actually need it!
private void ShowModuleExecuted()
{
WindowManager windowManager = new WindowManager();
Lazy<IModule, IModuleMetadata> selectedModule = _selectedModule;
IModule moduleToLoad = selectedModule.Value; //Only now we instantiate the module
windowManager.Show(moduleToLoad);
}


