Overview
When PostSharp gets a new assembly to process, it has to know which tasks the assembly should pass through. This is known as the requirements of the assembly towards PostSharp. The classical way to specify requirements is to provide a project file. However, it adds considerable complexity the end-user. And since we all cherish our end-users, we all want to make their live easier, don't we?
The idea behind the auto-detection feature is to guess the PostSharp requirements based on a basic analysis of the processed assembly.
PostSharp proposes two ways of auto-detecting requirements:
- referenced assemblies may have a custom attribute specifying PostSharp requirements, and
- custom attributes applied on the current assembly may have PostSharp requirements.
Inference of requirements from referenced assemblies
When applied to an assembly, say, MyAssembly, the
ReferencingAssembliesRequirePostSharpAttribute custom attribute
specifies that all assemblies that reference MyAssembly
have specific PostSharp requirements. This custom attribute allows
to specify which plug-in and which task should be used when
processing any referencing assembly. An assembly may contain many
instances of the
ReferencingAssembliesRequirePostSharpAttribute
attribute to insert more than one task or even plug-in.
The following code snippet is taken from the PostSharp.Laos assembly. It means that all assemblies referencing PostSharp.Laos should be processed using the PostSharp.Laos plug-in and the PostSharp.Laos task.
[assembly: ReferencedAssembliesRequirePostSharp("PostSharp.Laos", "PostSharp.Laos")]
Inference of requirements from custom attributes
PostSharp may also detect requirements based on the custom
attributes applied on the processed assembly or to any of its
elements (classes, fields, ...). These custom attributes should
implement the IRequirePostSharp
interface. At compile-time, PostSharp calls the
GetPostSharpRequirements method, which returns the
required set of plug-ins and tasks.
This method provides a finer-grain control than the one based on assembly references, but at the cost of performance. Note, however, that the expansive operations here (indexing types and custom attributes) are anyway performed later by many other tasks (for instance PostSharp Laos needs both), so the performance argument should be balanced.
Location of plug-ins
When you specify that a plug-in is required, you do it by giving its name. PostSharp will look in the search path for a file named exactly as you specified, excepted that it adds the.psplugin
extension.
Implementation
It is interesting to understand how the auto-detection of tasks (variant based on custom attributes) is implemented, because it illustrates many techniques of the Platform Infrastructure.
We build a hierarchy of types used or defined in the source assembly according to the base-derived relationship (TypeHierarchyTask).
The
CustomAttributeDictionaryTaskrequests all tasks providing custom attributes (ICustomAttributeProvider) and indexes these attributes by type.The ModuleCustomAttributeProvider task provides custom attributes defined in the source assembly.
The MulticastAttributeTask task provides custom attributes defined in the source assembly using the multicast mechanisms, i.e. custom attributes applied to many elements from a single definition using wildcards.
The AutoDetectTask loads in the current project all plug-ins and tasks that are required by custom attributes implementing the IRequirePostSharp interface.
Detected tasks are scheduled as usually according to their dependencies and are then executed.