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:

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.

  1. We build a hierarchy of types used or defined in the source assembly according to the base-derived relationship (TypeHierarchyTask).

  2. The CustomAttributeDictionaryTask requests all tasks providing custom attributes (ICustomAttributeProvider) and indexes these attributes by type.

    1. The ModuleCustomAttributeProvider task provides custom attributes defined in the source assembly.

    1. 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.

  3. The AutoDetectTask loads in the current project all plug-ins and tasks that are required by custom attributes implementing the IRequirePostSharp interface.

  4. Detected tasks are scheduled as usually according to their dependencies and are then executed.