Aspects can transform the target code by providing advice. Advice refers to a primitive transformation of code. It's safely composable, meaning that several aspects, even without knowledge of each other, can add advice to the same declaration.
Note
In English, the word advice is uncountable, i.e., grammatically uncountable. The grammatically correct singular form of advice is piece of advice, but using these words in a software engineering text seems unusual. In aspect-oriented programming, advice is a countable concept. Despite the challenges associated with using uncountable nouns as countable, we sometimes use an advice for the singular form and advices for the plural form, which may be occasionally surprising to some native English speakers. We use other neutral turns of phrases whenever possible unless it would make the phrase much more cumbersome or less understandable.
There are two methods to add advice: declaratively and imperatively.
Declarative advising
The only declarative advice is the member introduction advice, denoted by the IntroduceAttribute custom attribute. For each member of the aspect class annotated with [Introduce], the aspect framework attempts to introduce the member in the target class. For details, see Introducing members.
Imperative advising
Imperative advice is added by implementing the BuildAspect method, thanks to the advising extension methods exposed by the builder parameter implementing the IAdviser<T> interface.
The following methods are available:
- Override replaces the implementation of a method, field, property, event, or constructor.
- IntroduceMethod, IntroduceProperty, IntroduceField, and IntroduceEvent introduce new members into the target type. See Introducing members for details.
- ImplementInterface makes the target type implement an interface. See Implementing interfaces for details.
- IntroduceAttribute and RemoveAttributes add and remove custom attributes. See Adding or removing custom attributes for details.
- AddContract adds a pre-condition or post-condition to a field, property, or parameter. See Validating parameter, field, and property values with contracts for details.
- AddInitializer adds an initialization statement in the constructor or static constructor. See Adding initializers for details.
- IntroduceParameter appends a parameter to a constructor and pulls them from constructors of derived classes. See Introducing constructor parameters for details.
For a complete list of methods, see the AdviserExtensions class.
To advise a member of the current declaration (for instance, to override a method in the current type), get an adviser for the member by calling the IAdviser.With method.
Note
You can only advise the target of the current aspect instance or any declaration contained in this target. For instance, the BuildAspect method of a type-level aspect can advise all methods of the current type, including all parameters.
Template methods
With most types of advice, you must provide a template of the member you want to add to the target type.
Templates are written in standard C# code but combine two kinds of code: compile-time and run-time. When some target code is advised, the compile-time part of the corresponding template is executed. The output of this execution is the run-time code, which is then injected into the source code to form the transformed code.
For details, see Writing T# templates.