Open sandboxFocusImprove this doc

PS0116: Aspect Initialization Method of the Base Class Is Not Virtual

Severity Error
Reported by PostSharp
Message The method "<Method>" must be virtual and not sealed, because PostSharp needs to override it in the type "<DerivedType>" to initialize aspects.

Cause

To initialize the instance-scoped aspects of a class, PostSharp generates two methods without parameters in this class, InitializeAspects and OnInstanceConstructed, and calls them from the constructors. OnInstanceConstructed exists when an aspect has an OnInstanceConstructedAdvice. The methods are protected and virtual, so that a derived class that has aspects of its own overrides them and calls the method of its base class.

When a class already defines a method with one of these names and signatures, PostSharp uses it instead of generating one. When a derived class <DerivedType> needs the method and the base class defines it, PostSharp must override the method of the base class. It reports PS0116, on the method of the base class, when this method <Method> is not virtual or is sealed.

In the following example, the [TrackCreation] aspect of Invoice has an OnInstanceConstructedAdvice, and the base class EntityBase defines a non-virtual OnInstanceConstructed method.

using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;

namespace Errors.PS0116_Error;

// Reports the creation of each instance of the target class.
[PSerializable]
public class TrackCreationAttribute : InstanceLevelAspect
{
    [OnInstanceConstructedAdvice]
    public void OnInstanceConstructed() => Console.WriteLine( $"{this.Instance!.GetType().Name} created." );
}

internal class EntityBase
{
    public string Status { get; private set; } = "New";

    // PostSharp must override this method in Invoice, but it is not virtual.
    protected void OnInstanceConstructed()
    {
        this.Status = "Ready";
        Console.WriteLine( "Entity ready." );
    }
}

[TrackCreation]
internal class Invoice : EntityBase
{
}

public static class Program
{
    public static void Main()
    {
        Invoice invoice = new();
        Console.WriteLine( $"Status: {invoice.Status}" );
    }
}
error PS0116: PS0116_Error.cs(21,20): The method "Errors.PS0116_Error.EntityBase.OnInstanceConstructed" must be virtual and not sealed, because PostSharp needs to override it in the type "Errors.PS0116_Error.Invoice" to initialize aspects.

Resolution

  • Make the method of the base class protected virtual, and do not seal it in an intermediate class. PostSharp then overrides it in the derived class: the override calls the method of the base class and then the advices of the aspects. Note that PostSharp then calls your method after each constructor of the derived class.
  • Otherwise, rename the method of the base class, so that PostSharp generates its own methods.

In the following example, OnInstanceConstructed is virtual. PostSharp overrides it in Invoice and calls it when the instance is constructed.

using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;

namespace Errors.PS0116_Fixed;

// Reports the creation of each instance of the target class.
[PSerializable]
public class TrackCreationAttribute : InstanceLevelAspect
{
    [OnInstanceConstructedAdvice]
    public void OnInstanceConstructed() => Console.WriteLine( $"{this.Instance!.GetType().Name} created." );
}

internal class EntityBase
{
    public string Status { get; private set; } = "New";

    // PostSharp overrides this virtual method in Invoice.
    protected virtual void OnInstanceConstructed()
    {
        this.Status = "Ready";
        Console.WriteLine( "Entity ready." );
    }
}

[TrackCreation]
internal class Invoice : EntityBase
{
}

public static class Program
{
    public static void Main()
    {
        Invoice invoice = new();
        Console.WriteLine( $"Status: {invoice.Status}" );
    }
}
Entity ready.
Invoice created.
Status: Ready

See Also

Reference

OnInstanceConstructedAdvice
InstanceLevelAspect

Other Resources

Advice Methods
Developing Type- and Assembly-Level Aspects