The previous workshop demonstrated how you could make use of a “part” without the need to “new it up.” However, it provided no benefit over simply “newing it up.” You may as well have simply done this in the MainPage
class's constructor, like this:
MyImportedPersonPart = new PersonPart();
The MainPage
class is still tightly coupled to the PersonPart
class. The benefits of MEF are realized only when you make use of a contract to decouple them, exporting the part according to an interface instead of its concrete implementation. By taking a contract-based approach, you can then swap in alternative parts to the PersonPart
part, depending on the current scenario. This is particularly useful for improving the testability of your application, allowing you to import “mock” parts that help you to test a component in isolation from the rest of the application. It's also useful for creating a plug-in architecture, where plug-ins simply need to conform to a given interface in order for the application to be able to consume them, with MEF handling the discovering of the plug-ins.
A contract is just an interface that a part implements. A class tells MEF to import a part that implements that interface, and MEF will discover it and compose the two together. In this workshop, we'll refactor the code from the previous workshop and implement a contract to decouple the MainPage
and PersonPart
classes.
Name
. Add a new file to your project named IPersonPart.cs
, using the Code File item template. Add the following code to it:
namespace Chapter14Sample
{
public interface IPersonPart
{
string Name { get;set; }
}
}
Note An easier way to create this file is to right-click somewhere in the code for the PersonPart
class, and select Refactor Extract Interface from the context menu. The dialog that appears will help create the interface for you.
PersonPart
class implement this interface.
[Export]
public class PersonPart : IPersonPart
Export
attribute to export the part by its interface rather than its concrete implementation. You do this by passing the interface's type to the Export
attributes constructor, like so:
[Export(typeof(IPersonPart))]
public class PersonPart : IPersonPart
MyImportedPersonPart
property's type to IPersonPart
, as follows:
[Import]
public IPersonPart MyImportedPersonPart { get; set; }
The MainPage
class and PersonPart
class are now decoupled, with the MainPage
class now knowing nothing about the PersonPart
class, except the interface that it implements. MEF handles the discovery of the concrete implementation of the IPersonPart
interface, and injects it into the MainPage
class. If you now run your application, it will work exactly the same way as it did before.