Open sandboxFocusImprove this doc

Adding Aspects Programmatically Using IAspectProvider

In some situations, you may want to implement an aspect as part of a larger pattern. For example, you may want to add an aspect, implement an interface and dynamically inject some logic into the target code. In those situations, apply an aspect to the target code and let that aspect add other aspects to other elements of code.

The following steps show the implementation.

  1. Create an aspect that implements the IAspectProvider interface.

    [PSerializable]
    public class ProviderAspect : TypeLevelAspect, IAspectProvider 
     { 
        public IEnumerable<AspectInstance> ProvideAspects(object targetElement) 
        { 
            throw new System.NotImplementedException(); 
        } 
     }
    
  2. Cast the target object parameter to the type that will be targeted by this aspect: Assembly, Type, FieldInfo, MethodBase, PropertyInfo, EventInfo, ParameterInfo or LocationInfo.

    public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
    {
       Type type = (Type) targetElement;
    
       throw new NotImplementedException();
    }
    
  3. Return an AspectInstance of the aspect type you want for every target element of code. The target elements must be inside the element of code to which the provider aspect is applied. For instance, a type-level provider can add aspects to the methods of its own type, but not to the methods of other types.

    public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
    {
        Type type = (Type)targetElement;
    
        return type.GetMethods( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly ).Select(
           m => new AspectInstance(m, new LoggingAspect() ) );
    
    }
    

This aspect now adds aspects dynamically at build time. The IAspectProvider interface is usually reserved for situations where you implement a larger design pattern. For example, you can use it to implement an aspect that creates the NotifyPropertyChangedAttribute pattern across a large number of locations in your codebase. It is more than many situations require. Use it only for aspects that implement complex patterns.

Note

Aspects provided by IAspectProvider are initialized like other aspects: PostSharp calls their CompileTimeInitialize method at build time and their RunTimeInitialize method at run time.

Creating Graphs of Aspects

It is common that aspects provided by IAspectProvider (child aspects) form a complex object graph. For instance, child aspects may contain a reference to the parent aspect.

PostSharp serializes object graphs that are instantiated at build time, so they can be used at run time. In other words, if you store a reference to another aspect in a child aspect, you will be able to use this reference at run time.

Extension Block Members

C# 14 introduced extension members. Both IAspectProvider and IAdviceProvider can be used on extension member implementation methods (members of the class containing extension blocks).

Targeting extension block metadata types (nested types emitted by the C# compiler) and all their members will result in an error LA0167. You can use <xref:PostSharp.Reflection.ReflectionHelper.IsExtensionBlockMetadata> to identify extension block metadata members if filtering is needed.

See Also

Reference

IAspectProvider
NotifyPropertyChangedAttribute
ProvideAspects(object)
AspectInstance

Other Resources

INotifyPropertyChanged
Handling Corner Cases of the NotifyPropertyChanged Aspect
C# 14 Extension Members - Microsoft Learn
Exploring extension members - .NET Blog