| Severity | Error |
| Reported by | PostSharp |
| Message | The method "<Method>" must be "public virtual" or "protected virtual", and not sealed, because PostSharp uses it to initialize aspects and its declaring type is visible outside the assembly. |
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 when an instance is constructed. OnInstanceConstructed exists when an aspect has an OnInstanceConstructedAdvice. When the class already defines a method with one of these names and signatures, PostSharp uses it instead of generating one, and adds its code to it.
A derived class, possibly in another assembly, must be able to override this method to initialize its own aspects. So when the declaring type is visible outside the assembly and is not sealed, PostSharp reports PS0117 when the method <Method> is not virtual, is sealed, or is not visible outside the assembly (private or internal).
In the following example, the public class Invoice has an aspect with an OnInstanceConstructedAdvice, and defines a non-virtual OnInstanceConstructed method.
using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.PS0117_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." );
}
[TrackCreation]
public class Invoice
{
public string Status { get; private set; } = "New";
// PostSharp needs this method to be public virtual or protected virtual.
public void OnInstanceConstructed()
{
this.Status = "Ready";
Console.WriteLine( "Invoice ready." );
}
}
public static class Program
{
public static void Main()
{
Invoice invoice = new();
Console.WriteLine( $"Status: {invoice.Status}" );
}
}
error PS0117: PS0117_Error.cs(22,17): The method "Errors.PS0117_Error.Invoice.OnInstanceConstructed" must be "public virtual" or "protected virtual", and not sealed, because PostSharp uses it to initialize aspects and its declaring type is visible outside the assembly.
Resolution
- Make the method
protected virtualorpublic virtual, and do not seal it. PostSharp then adds its code to your method, after your code, and calls the method when an instance is constructed. - Otherwise, rename the method, so that PostSharp generates its own one. Do this when your method is not meant to run at construction time.
- When the class does not need derived classes, make it
sealed: the rule then does not apply.
In the following example, OnInstanceConstructed is protected virtual. PostSharp calls it after the constructor, then runs the advice of the aspect.
using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.PS0117_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." );
}
[TrackCreation]
public class Invoice
{
public string Status { get; private set; } = "New";
// PostSharp adds the advice to this method and calls it after the constructor.
protected virtual void OnInstanceConstructed()
{
this.Status = "Ready";
Console.WriteLine( "Invoice ready." );
}
}
public static class Program
{
public static void Main()
{
Invoice invoice = new();
Console.WriteLine( $"Status: {invoice.Status}" );
}
}
Invoice ready.
Invoice created.
Status: Ready
See Also
Reference
OnInstanceConstructedAdvice
InstanceLevelAspect
Other Resources