This can be described by an example. For instance, let's say you have a core library that you base all your bespoke applications on. Call it MyCompany.Core. Normally, every application you write has to contain a reference to MyCompany.Core, and then the application has to take care of bootstrapping and calling into MyCompany.Core to start the appropriate services, etc., in the correct order. This doesn't make much sense when you consider that the core itself probably knows better how it's supposed to be started up, etc.
To use MEF for dependency injection, your core would do this:
[Import("/Application", typeof(IBespokeApplication))]
private IBespokeApplication bespokeApplication;
The core itself would contain the application startup code, and might call something like this once it had started up all of its services:
bespokeApplication.Start();
In the bespoke application, you have to export yourself:
[Export("/Application", typeof(IBespokeApplication))]
public class MyApplication : IBespokeApplication
{
public void Start()
{
/* start app */
}
}
Now the bespoke application could contain a direct reference to MyCompany.Core, and could call services directly, or you could even expose the services as Exports and Import them into the application. For instance, in the core:
[Export("/LoggingService", typeof(ILoggingService))]
public class NLogLoggingService : ILoggingService
{
/* ... */
}
Then in the bespoke application:
[Import("/LoggingService", typeof(ILoggingService))]
private ILoggingService loggingService;
...and when you want to use it:
loggingService.LogInformation("My Message");
As far as I can tell from the literature, that's the essence of dependency injection.