Transforming code: concepts
Aspects can transform the target code by providing advice. An advice is a primitive transformation of code. Advice is safely composable: several aspects that do not know about each other can add advice to the same declaration.
In English, the word advice_is uncountable, i.e., grammatically plural. The grammatically-correct singular form of _advice is piece of advice, but using these words in a software engineering text seems very odd. In aspect-oriented programming, advice is a countable concept. Despite the difficulties 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 shocking 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 ways to add advice: declaratively and imperatively.
The only declarative advice is the member introduction advice marked by the IntroduceAttribute custom attribute. For each member of the aspect class annotated with
[Introduce], the aspect framework will attempt to introduce the member in the target class. For details, see Introducing members.
Imperative advice is added by implementing the BuildAspect method, thanks to the methods exposed by the Advice property of the
builder parameter. See IAdviceFactory for a complete list of methods. In short:
- Override allows you to replace the implementation of a type member.
- IntroduceMethod, IntroduceProperty, IntroduceField and IntroduceEvent allows your aspect to 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.
With most kinds 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 mix 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 make up the transformed code.
For details, see Writing T# templates.