Run-Time Weaving

Transparent proxies, RealProxy and ContextBoundObject

The idea here is to put a proxy between the woven class and the consumer. It uses
the same mechanism as in remoting: the client 'see' the remote object, but it actually
talks to its proxy. All accesses to the aspected object go through the proxy class.
The aspect is implemented as a transparent proxy, derived from the System.Runtime.Remoting.Proxies.RealProxy
class.

There are tree ways to tell that an object should be accessed to a proxy:

If the aspected class is derived from ContextBoundObject, apply
the System.Runtime.Remoting.Proxies.ProxyAttribute to this class in order
to specify which proxy class should be used.

If the aspected class is derived
from MarshalByRefObject, the method RealProxy.GetTransparentProxy()
can be called in order to retrieve the proxy of an existing instance. But this means
that user code cannot use constructors to get instances of aspected objects, but
should use instead factory methods.

Otherwise, the aspected class should expose
all its semantics on an interface.

These methods have thus the disadvantages of restricting the aspectable methods
to instance methods of classed derived from ContextBoundObject or MarshalByRefObject.
What is more, the only possible join points are method boundaries, as with the previous
approach.

Load-Time
Static Weaving

This approach is very similar to Compile-Time
Weaving, but occurs it occurs at runtime just before the assembly is loaded
in memory. This situation is adequate when changing the aspects can
require the application to be restarted. In its pure application, it does not enable
a true dynamic weaving. PostSharp fully supports this scenario.

A variant of this approach is to add join point to code using static weaving, but
add advices to join points at runtime, i.e. without restarting the application.
It is not difficult to realize this using PostSharp, but it is not ready as an out-of-the-box
feature. The disadvantage of this variant is of course that one should choose a
balance between join point density (and so flexibility) and performance. Too many
join points will produce a huge and slow code.

JIT Emission
of Classes

This approach works only with public virtual methods and with interfaces. There
are two approaches: the first is to generate a proxy class implementing the semantics
of an interface. In this case, only interface methods can be aspected. The second
approach is to generate a child class inherited from the aspected class; it requires
this class to be unsealed and it is limited to virtual methods.

The System.Reflection.Emit namespace can be used. Besides of being limited
to interface or virtual methods, this approach only supports the join points located
at method boundaries (on entry, on exit, on exception).

Profiler API

The Unmanaged Profiler API of the .NET Framework is initially intended to instrument
the code, typically for memory and processor consumption. The same API can be used
to execute virtually any code. Since the granularity of the Profiler API is very
fine, it is possible to define a large range of join points. The outcome however
is that the code has to be executed besides the profiler, which is not aimed to
be used in production. This makes this approach inappropriate for commercial software.

Debugger API & Edit and Continue

The idea here is partially similar to the use of the Profiler API, but additionally
the edit-and-continue facility can be used to modify MSIL code at runtime. This
has the potential to get faster code than with the Profiler API. However, it has
the same disadvantages, that is, it is little appropriate for commercial software.