MEF for Beginner (Part Creation Policy) – part 6
this post and a few that will follow will cover some of the policies options available with MEF.
we will start with the instantiation policy.
How do we define policy?
we will define policy as instruction that will guide behavioral decisions that related
to the compose-able parts (the imported and exported parts behaviors).
What is instantiation policy (part creation policy)?
the instantiation policy, is the instruction for how parts should be instantiate.
there is 2 instantiation options:
- Shared: is a singleton model, which mean that exported part instantiation will instantiate once
(not matters how many time this part was requested).
- Non Shared: will create new instance each time we are asking for exportable part.
What is the default instantiation?
the default instantiation model of MEF is the singleton model.
the best-practice is to use the Shared (singleton) model.
this bring us to design consideration which suggest that you should design your
exportable parts as stateless and thread safe, so they won’t be affected
by multiple calls (maybe on different threads) upon the same instance.
in cases that the singleton model is not suitable for you, it is recommended
to use builder pattern (to separate the exported part from the actual instantiation).
you should remember that using the non shared model is quite costly because
it is using reflection for the actual instantiation (by using the builder pattern you
can gain the same result with less pain).
How to define our instantiation model?
out of the box we having the [PartCreationPolicy] attribute which make it fairly simple
to define instantiation policy.
here is code snippet that using the [PartCreationPolicy] attribute, which I will immediately discuss:
at lines 1,2: we can see the contract definition (the contract does not dictate the creation policy)
the InheritedExport attribute means that any type derived from the contract will be automatically exported.
line 4: is decorating Person1 class to apply to the shared (singleton) model.
so no matter how many times Person1 will be imported it will always be the same instance.
line 7: is decorating Person2 class to apply to the non shared model.
so different instance of Person2 will be assigned for each import.
line 10: at the moment this could be somewhat puzzling but we will shortly clear this out.
in terms of instantiation this is the default and it is equivalent to the shared declaration
(unless the import decoration is explicitly asking for non shared policy).
so you may ask yourself why should they add this option if it equivalent to the shared one?
the answer for this question can be found in the next paragraph.
How to restrict our import discovery for specific instantiation model?
the default setting of Import / ImportMany is equivalent to the next snippet:
CreationPolicy.Any means that our import does not care about the instantiation model
of the parts, so the MEF discovery can assign any parts that match the IPerson contract.
the PersonsDefault property will be assigned with Person1, Person2 and Person3.
sometimes we want to be more explicit about what type of instantiation allowed for the import.
for those scenarios we can use the following decorations:
line 1: restrict the MEF assignment of PersonShared property to exported parts that created
under the shared policy, which is means parts that decorated with CreationPolicy.Shared or CreationPolicy.Any.
PersonsShared property will be assigned with Person1 and Person3.
line2: restrict the MEF assignment of PersonNonShared property to exported parts that created
under the non shared policy, which is means parts that decorated with CreationPolicy.NonShared or CreationPolicy.Any
(in this case the part that decorated with the CreationPolicy.Any will not instantiate as a singleton).
PersonsShared property will be assigned with Person2 and Person3.
MEF instantiation is singleton by default, but this policy can be altered.
you can find code sample that demonstrate the different creation policies here.