| 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