Accessing Members of the Target Class

PostSharp makes it possible to import a delegate of a target class method, property or event into the aspect class, so that the aspect can invoke this member.

These mechanisms allow developers to encapsulate more design patterns using aspects.

This topic contains the following sections.

  • Importing Members of the Target Class
  • Interactions Between Several Member Introductions and Imports
  • Examples
Importing Members of the Target Class

Importing a member into an aspect allows this aspect to invoke the member. An aspect can import methods, properties, or fields.

To import a member of the target type into the aspect class:

  1. Define a field into the aspect class, of the following type:

    Member Kind

    Field Type

    Method

    A typed Delegate, typically one of the variants of Action or FuncTResult. The delegate signature should exactly match the signature of the imported method.

    Property

    PropertyTValue, where the generic argument is the type of the property.

    Collection Indexer

    PropertyTValue, TIndex, where the first generic argument is the type of the property value and the second is the type of the index parameter. Indexers with more than one parameter are not supported.

    Event

    EventTDelegate, where the generic argument is the type of the event delegate (for instance EventHandler).

  2. Make this field public. The field cannot be static.

  3. Add the custom attribute ImportMemberAttribute to the field. As the constructor argument, pass the name of the member to be imported.

At runtime, the field is set to a delegate of the imported member. Properties and events are imported as set of delegates (PropertyTValueGet, PropertyTValueSet; EventTDelegateAdd, EventTDelegateRemove). These delegates can be invoked by the aspect as any delegate.

The property ImportMemberAttributeIsRequired determines what happens if the member could not be found in the target class or in its parent. By default, the field will simply have the null value if it could not be bound to a member. If the property IsRequired is set to true, a compile-time error will be emitted.

Interactions Between Several Member Introductions and Imports

Although member introduction and import may seem simple advices at first sight, things become more complex when the several advices try to introduce or import the same member. PostSharp handles these situations in a robust and predictable way. For this purpose, it is primordial to process classes, aspects and advices in a consistent order.

PostSharp enforces the following order:

  1. Base classes are processed first, derived classes after. Therefore, when a class is being processed, all parent classes have already been fully processed.

  2. Aspects targeting the same class are sorted (see Coping with Several Aspects on the Same Target) and executed.

  3. Advices of the same aspect are sorted and executed in the following order:

    1. Member imports which have the property ImportMemberAttributeOrder set to BeforeIntroductions.

    2. Member introductions.

    3. Members imports which have the property ImportMemberAttributeOrder set to AfterIntroductions (this is the default value).

Based on this well-defined order, the advices behave as follow:

Advice

Precondition

Behavior

ImportMemberAttribute

No member, or private member defined in a parent class.

Error if ImportMemberAttributeIsRequired is true, ignored otherwise (by default).

Non-virtual member defined.

Member imported.

Virtual member defined.

If ImportMemberAttributeOrder is BeforeIntroductions, the overridden member is imported. This similar to calling a method with the base prefix in C#. Otherwise (and by default), the member is dynamically resolved using the virtual table of the target object.

IntroduceMemberAttribute

No member, or private member defined in a parent class.

Member introduced.

Non-virtual member defined in a parent class

Ignored if the property IntroduceMemberAttributeOverrideAction is Ignore or OverrideOrIgnore, otherwise fail (by default).

Virtual member defined in a parent class

Introduce a new override method if the property IntroduceMemberAttributeOverrideAction is OverrideOrFail or OverrideOrIgnore, ignore if the property is Ignore, otherwise fail (by default).

Member defined in the target class (virtual or not)

Fail by default or if the property IntroduceMemberAttributeOverrideAction is Fail.

Otherwise:

  1. Move the previous method body to a new method so that the previous implementation can be imported by advices ImportMemberAttribute with the property Order set to BeforeIntroductions.

  2. Override the method with the imported method.

Examples
See Also